站在持久化的角度, Hibernate 把对象分为 4 种状态:
1. 持久化状态
2. 临时状态
3. 游离状态
4. 删除状态
Session 的特定方法能使对象从一个状态转换到另一个状态.
下面是各状态之间的转换图, 以及如何转换的:
准备工作:
1. 建立持久化类
Person类
package com.hibernate.entities; public class Person { private Integer id; private String name; private Integer age; public Person() { super(); } public Person(String name, Integer age) { super(); this.name = name; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
2. 建立持久化类的映射文件
Person.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.hibernate.entities.Person" table="PERSONS"> <id name="id" type="java.lang.Integer"> <column name="ID" /> <generator class="identity" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <property name="age" type="java.lang.Integer"> <column name="AGE" /> </property> </class> </hibernate-mapping>
3. 建立Hibernate的主配置文件 hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 配置连接数据库的信息 --> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">oracle</property> <property name="hibernate.connection.url">jdbc:mysql:///hibernate</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 配置数据库方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQL57InnoDBDialect</property> <!-- 设置数据表生成策略 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 是否格式化SQL --> <property name="hibernate.format_sql">true</property> <!-- 是否显示SQL --> <property name="hibernate.show_sql">true</property> <!-- 修改delete()的默认行为, 使删除对象的OID变为null --> <property name="hibernate.use_identifier_rollback">true</property> <!-- 添加配置文件 --> <mapping resource="com/hibernate/entities/Person.hbm.xml"/> </session-factory> </hibernate-configuration>
4. 建立单元测试类
package com.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.annotations.SelectBeforeUpdate; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; public class TestHibernate { private SessionFactory sessionFactory; private Session session; private Transaction transaction; @Before public void init(){ sessionFactory = new Configuration().configure().buildSessionFactory(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); } @After public void distory(){ transaction.commit(); session.close(); sessionFactory.close(); } }
这里我直接把注释, 说明等文字写在代码里了,可以直接复制下来, 放到IDE开发工具里面慢慢看
package com.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.annotations.SelectBeforeUpdate; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.hibernate.entities.Person; public class TestHibernate { private SessionFactory sessionFactory; private Session session; private Transaction transaction; @Before public void init(){ sessionFactory = new Configuration().configure().buildSessionFactory(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); } @After public void distory(){ transaction.commit(); session.close(); sessionFactory.close(); } /* * 站在持久化的角度: * Hibernate 把对象分为 4 种状态: * 持久化状态, 临时状态, 游离状态, 删除状态. * Session 的特定方法能使对象从一个状态转换到另一个状态. */ /* * 一: 临时对象(Transient) * 1. 在使用代理主键的情况下, OID 通常为 null * 2. 不处于 Session 的缓存中 * 3. 在数据库中没有对应的记录 */ /* * 二: 持久化对象(也叫"托管")(Persist) * 1. OID 不为 null. * 2. 位于Session缓存中. * 3. 若在数据库中已经有和其对应的记录, 持久化对象和数据库中的相关记录对应. * 4. Session在flush缓存时, 会根据持久化对象的属性变化, 来同步更新数据库. * 5. 在同一个Session实例缓存中, 数据库表中的每条记录只对应唯一的持久化对象. */ /* * 三: 删除对象(Removed) * 1. 在数据库中没有和其OID对应的记录. * 2. 不再处于Session缓存中. * 3. 一般情况下, 应用程序不再使用该对象. */ /* * 四: 游离对象(也叫"托管")(Detached) * 1. OID不为null. * 2. 不再处于Session缓存中. * 3. 一般情况下, 游离对象是持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录. */ /** * save()方法:使一个临时对象转变为持久化对象. * 执行save()方法时, 系统会完成以下操作: * 1. 把 new 对象加入到Session缓存中, 使它进入持久化状态. * 2. 选用映射文件指定的标示符生成器, 为持久化对象分配唯一的OID. * 在使用中代理主键的情况下, setId() 方法为 new 对象设置的OID 是无效的. * 3. 计划执行一条 insert 语句(在flush缓存的时候). * persist()方法: 同save()方法. */ @Test public void testSaveOrPersist(){ // 保存一个对象 // Person person = new Person("Tom", 12); // session.save(person); // 使用 save() 保存一个有id值的对象时, 正常保存. // Person person = new Person("Tom", 12); // person.setId(100); // session.save(person); // 使用 persist()保存一个有id值得对象时, 抛异常! // Person person = new Person("Mike", 23); // person.setId(100); // session.persist(person); // 试图修改持久化对象的 ID, 不允许! // Person person = session.get(Person.class, 1); // person.setId(1000); // session.update(person); } /** * get() 和 load() 方法 * 相同点: * 都可以根据指定的OID, 从数据库中加载一个持久化对象. * 不通电: * 1. 当数据库不存在OID对应的记录时: * load() 会抛出异常. * get() 返回null. * 2. 两者采用不同的加载策略: * load() 支持延迟加载. * get() 不支持. */ @Test public void testGetOrLoad(){ // 1. 使用 get() 获取对象 // 当调用 get() 时, Hibernate会计划执行SQL, 在flush时的时候, 会发送SQL语句. // session.get(Person.class, 2); // session.flush(); // System.out.println("======================"); // 2. 使用 load() 延迟加载对象 // 当调用 load() 时, Hibernate不会计划执行SQL // 即使flush操作的时候, 如果没有使用这个对象, 那么Hibernate就不会发送SQL语句. // 只有在使用这个对象的时候, Hiberante才会发送SQL语句. 这就是延迟加载! Person person = session.load(Person.class, 2); session.flush(); System.out.println("======================"); System.out.println(person.getName()); } /** * 1. update(): 使一个游离对象转变为持久化对象, 并且计划执行一条SQL语句. * 2. 如果希望Session仅当修改了 new 对象的属性时, 才执行 update 语句 * 可以把映射文件中的<class>元素的 select-before-update 设置为true, 默认为false. * 3. 当 update() 关联一个游离对象时, 如果在Session的缓存中已经存在相同OID的持久化对象, 会抛异常! * 4. 当 update() 关联一个游离对象时, 如果在数据库中不存在相应的记录, 也会抛出异常! */ @Test public void testUpdate(){ // 一: 正常的 update // // tip:游离对象是由持久化对象转换过来的. // Person person = session.get(Person.class, 1); // transaction.commit(); // // session 关闭后, person 对象转换为游离对象. // session.close(); // session = sessionFactory.openSession(); // transaction = session.beginTransaction(); // person.setAge(19); // // 执行完 update, person对象由游离对象转变为持久化对象. // session.update(person); // 二: 当在配置文件添加 select-before-update=true 的时候 // 这里我们用注释来做, 在类上加上: @SelectBeforeUpdate(value=true) // 1. 没有改变任何属性, 当时Hibernate仍然发送一条SQL语句来验证属性值是否改变. // Person person = session.get(Person.class, 1); // session.update(person); // 2. 改变了属性之后, 不仅发送一条SQL语句, 还会发送一条update语句. // Person person = session.get(Person.class, 1); // person.setName("Kim"); // session.update(person); // 三: Session缓存中存在相同的OID. // // 先获取一个持久化Person, 然后关闭Session变为游离态. // Person person1 = session.get(Person.class, 1); // transaction.commit(); // session.close(); // session = sessionFactory.openSession(); // transaction = session.beginTransaction(); // // 开启Session, 再获取一个相同的Person对象 // Person person2 = session.get(Person.class, 1); // person1.setName("Sunny"); // // 把游离态的person1转化为持久化态, 由于我们缓存中已经有一个OID为1的person2 // // 所以抛异常!(Hibernate不允许缓存中存在OID相同的对象) // session.update(person1); // 四: 数据库中不存在相应的记录 // 意味着这是一个临时对象, 或者删除对象 // 只能执行save()或者persist()进行持久化 // update() 只能把游离对象, 转化为持久化对象 // Person person = new Person("Lily", 15); // // 抛异常! // session.update(person); } /** * saveOrUpdate(): 包含了 save() 和 update() 的功能 * 如果是一个临时对象, 就执行save() * 如果是一个持久化对象, 就执行update() * 判断是临时对象的标准: * 1. 如果对象的OID为null. * 2. 映射文件中<id> 设置了 unsaved-value 属性, * 并且java对象的OID取值与这个unsaved-value属性值匹配. */ @Test public void testSaveOrUpdate(){ // id(OID)值为null, 执行 insert 语句 // Person person = new Person("Mike", 15); // session.saveOrUpdate(person); // id(OID)值为unsaved-value的值(100), 执行insert语句 // Person person = new Person("Mike", 15); // person.setId(100); // session.saveOrUpdate(person); // 数据库中有与id(OID)值对应的值, 那么就执行update语句 Person person = new Person("Mike", 15); // 数据库中有主键为2的数据, 执行update语句 person.setId(2); session.saveOrUpdate(person); } /** * merge() */ @Test public void testMerge(){ /* * 一: 临时对象 * 创建一个新的News对象,把new1对象的属性拷贝到新建的News对象中 * 持久化这个News对象,计划执行一条insert语句 */ // Person person = new Person("Tom", 13); // // 发送了一条insert // session.merge(person); /* * 二: 游离对象 + 存在Session缓存中 */ // Person person1 = session.get(Person.class, 1); // // guanbiSession, 开启Session使对象变为游离态 // transaction.commit(); // session.close(); // session = sessionFactory.openSession(); // transaction = session.beginTransaction(); // // 重新加载到Session缓存中. // Person person2 = session.get(Person.class, 1); // person1.setName("Mike"); // // 把person1对象的属性拷贝到person2持久化对象中,计划执行一条update语句 // // 发送了2条select, 1条update // session.merge(person1); /* * 三: 游离对象 + 不存在Session缓存中 + 数据库中存在id为1的记录 */ // Person person = session.get(Person.class, 1); // transaction.commit(); // session.close(); // session = sessionFactory.openSession(); // transaction = session.beginTransaction(); // person.setName("Kim"); // // 从数据库加载id为1的News持久化对象(会发送一条select) // // 把person对象的属性拷贝到News持久化对象中,计划执行一条update语句 // // 发送了2条select, 1条update // session.merge(person); /* * 四: 游离对象 + 不存在Session缓存中 + 数据库中不存在id为1的记录 */ // // 1 条select // Person person = session.get(Person.class, 1); // // 从数据库中删除, 1 条delete // session.delete(person); // transaction.commit(); // session.close(); // session = sessionFactory.openSession(); // transaction = session.beginTransaction(); // // 1 一条insert // session.merge(person); } /** * delete(): 既可以删除一个游离对象, 也可以删除一个持久化对象 * 处理过程: * 1. 计划执行一条 delete 语句 * 2. 把对象从 Session缓存中移除, 该对象进入删除状态 * hibernate.use_identifier_rollback 属性: * 这个值默认为false, 如果改为true, 将改变 delete()的运行行为, * delete()会把持久化对象或游离对象的OID置为null, 使它们变为临时对象 */ @Test public void testDelete(){ // 1. hibernate.use_identifier_rollback=false // Person person = session.get(Person.class, 3); // session.delete(person); // session.flush(); // // 打印 3 // System.out.println(person.getId()); // 2. hibernate.use_identifier_rollback=true Person person = session.get(Person.class, 3); session.delete(person); session.flush(); // 打印 null System.out.println(person.getId()); } }