Hibernate中java对象的三种状态
瞬时状态(Transient):通过NEW创建对象后对象并没有立刻持久化他未与数据哭中的数据有任何关联
持久状态(Persistent):当对象与Session关联,被管理时他就处于持久常态.
游离状态(Detached):处于持久状态,脱离与其相关的Session的管理后对象就处于游离状态.
该图从类型上划分为"活动图"
开始●:对象声明的开始。
结束⊙:对象销毁了。
关于load()和get()方法区别的说明
Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象。
其区别在于:
如果未能发现符合条件的记录,get方法返回null,而load方法会抛出一个ObjectNotFoundException。
Load方法可返回实体的代理类实例,而get方法永远直接返回实体类。
load和个体方法都可以充分利用内部缓存和二级缓存中的现有数据。
脏检查及刷新缓存机制
脏检查:当事务提交时,Hiberante会对Session中持久状态的对象进行检测,判断对象的数据是否发生了改变
如何脏检查?
解析:当一个Dept对象被加入到Session缓存(有人又称为 一级缓存 后者是内部缓存)中时,Session会为Dept对象的值类型的属性复制一份快照。当Session刷新缓存时,会先进行脏检查,即比较Dept对象的当前属性与它的快照,来判断Dept对象的属性是否发生了变化。如果发生了变化,Session会根据脏对象的最新属性值来执行相关的SQL语句,将变化更新到数据库中。
Session具有一个缓存,可以管理和跟踪所有持久化对象,对象和数据库中的相关记录对应。
当事务提交时,Hibernate会对Session中持久状态的对象进行检测,判断对象的数据是否发生了改变,这种判断称为脏检查
Session session;
Transaction tx; @After
public void afterTest(){
tx.commit();
HibernateUtil.closeSession();
} @Before
public void initDate(){
session=HibernateUtil.getSession();
tx = session.beginTransaction();
} @Test
//延迟加载
public void loadTest(){
Student stu = (Student)session.load(Student.class, 1);
System.out.println("ok");
System.out.println(stu);
} @Test
public void getTest(){
Student stu = (Student)session.get(Student.class, 1);
//脏检查
stu.setName("猪");
}
刷新缓存机制
当Session缓存中对象的属性每次发生变化时,Session并不会立即刷新缓存和执行相关的SQL语句,而是在特定时间点才刷新缓存
什么是序列化
对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能力叫作对象的持续性(persistence)。对象通过写出描述自己状态的数值(serialVersionUID)来记录自己 ,这个过程叫对象的串行化(Serialization) 。串行化的主要任务是写出对象实例变量的数值以控制持久化对象的版本。如果该变量是另一对象的引用,则引用的对象也要串行化。这个过程是递归的。
持久化
序列化是能够实现对象的写入和写出,这样在此基础上,持久化就水到渠成了。持久化是将程序数据在持久状态和瞬时状态间转换的机制。JDBC就是一种持久化机制。文件IO也是一种持久化机制。在一定周期内保持不变就是持久化,持久化是针对时间来说的。持久化就是把内存中的对象保存到外存中,让以后能够取回。而保存和取回的过程就是经过序列化和对象io完成的。
序列化是为了解决对象的传输问题,使对象传输可以在线程之间、进程之间、内存外存之间、主机之间进行。我之所以在这里提到序列化,是因为我们可以利用序列化来辅助持久化。
Hibernate JDBC 警告的清楚
未添加log4j.properties
添加log4j.properties 并修改红框圈起来的位置
24.Hibernate常用配置
<!-- Echo all executed SQL to stdout 是否在控制台打印后台Hibernate生成的sql --> <property name="show_sql">true</property> <!-- 格式化SQL语句 --> <property name="format_sql">true</property> <!-- 自动生成建表语句 create update validate create-drop--> <property name="hbm2ddl.auto">update</property>
主键生成策略
increment
identity
sequence
native
uuid
assigned
1) increment
由hibernate完成 主键递增,
原理:select max(id) , insert时max(id)+1 ,完成主键递增
优点:跨数据库
缺点:多线程并发访问问题(第一个线程执行成功,第二个线程报错)
2) identity
由底层数据库来完成自增 ,要求数据库必须支持自增主键 mysql支持 ,oracle不支持
3) sequence
编号列生成由底层数据库提供序列,来完成主键自增,要求数据库必须支持序列 mysql不支持,oracle支持
create sequence myseq; 创建序列
insert into customer values (myseq.nextval); 插入数据时调用序列,序列+1
4) native
采用数据库支持自增策略, mysql就用identity 、oracle就用sequence
策略1) ---> 策略4) 要求数据库主键必须为数字 ,因为只有数字才能自增
5) uuid
32位 唯一字符串, 主键使用varchar 类型
真实开发中,用程序提供uuid值
6) assigned
手动指定主键的值,该主键一般有实际意义,例如订单单号(20160114-A002)20160114-B001 20160114-C002。
复合主键,是一种特殊 assigned类型 自然主键 (通常需要手动指定),PO类必须实现Serializable接口
<class name="cn.happy.entity.Person" table="person">
<composite-id>
<key-property name="firstname"></key-property>
<key-property name="secondname"></key-property>
</composite-id>
</class>
持久化对象的唯一标识OID
Java中安内存地址不同区分同一个类的不同对象
关系数据库用主键区分同一条记录
Hibernate使用OID来建立内存中的对象和数据库中记录的对应关系
01.什么是OID?
解析:OID 是持久化类(Student)与数据表主键对应属性, 用来唯一区分持久化对象。
02.尽量使用包装类
解析:一个学生成绩为0,无法区分是参加了考试考取了0分,还是没有成绩。
如果使用包装类,数据库就会存入null,证明该学生没有参加考试
快照
Oracle分页三层嵌套 :性能最高
select * from
(
Select emp.*,rownum as rn
from
(
select * from emp
)emp
where rownum<=9
)
where rn>=7
这是由于CBO优化模式下,Oracle可以将外层的查询条件推到内层查询中,以提高内层查询的执行效率。对于第一个查询语句,第二层的查询条件WHERE ROWNUM <= 40就可以被Oracle推入到内层查询中,
这样Oracle查询的结果一旦超过了ROWNUM限制条件,就终止查询将结果返回了。
第一个入门案例
1.构建了一个Student实体类
public class Student {
private Integer id;
//name
private String name;
//age
private Integer age;
}
2.构建一个大配置
在src根目录下书写
Hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
<property name="connection.username">sb</property>
<property name="connection.password">sb</property>
<!-- 输出所有 SQL 语句到控制台。 -->
<property name="hibernate.show_sql">true</property>
<!-- 在 log 和 console 中打印出更漂亮的 SQL。 -->
<property name="hibernate.format_sql">true</property>
<!-- 方言 -->
<property name="hibernate.dialect"> org.hibernate.dialect.Oracle10gDialect</property>
<!-- 关联小配置 -->
</session-factory>
</hibernate-configuration>
3.构建小配置,和实体类对应的
Student.hbm.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.happy.entity">
<class name="Student" table="Student">
<id name="id" type="int" column="id">
</id>
<property name="name" type="string" column="name"/>
<property name="age" type="int" column="age"/>
</class>
</hibernate-mapping>
4.测试代码
对session进行探究。
Session.save(stu);
package cn.happy.test;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test;
import cn.happy.entity.Student;
public class H_01Test {
@Test
public void testAdd(){
//1.1构建一个学生对象
Student stu=new Student();
stu.setAge(18);
stu.setName("2016年8月28日09:21:09训练营");
stu.setId(3);
//1.2 找到和数据库的接口 session--->sessionFactory--->configure.buildSessionFactory()
Configuration cf=new Configuration().configure("hibernate.cfg.xml");
SessionFactory factory = cf.buildSessionFactory();
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
//1.3保存
session.save(stu);
tx.commit();
session.close();
}
}