问题导入
@Test
public void testUnclear(){
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
//获取对象
Person person=(Person) session.get(Person.class, 1L);
//创建另外一个对象
Person person2=new Person();
person2.setPid(1L);
person2.setPname("ansel");
//执行update语句
session.update(person2);
transaction.commit();
session.close();
}
点执行的时候,报错了。
原因是不同的对象有相同的主键,这个毫无疑问,数据库要保证主键的唯一性。
可是当我把第12行注释之后,运行通过了
那么,session.update这一行到底有什么魔力呢?可是在后面把上面第12行注释之后,为什么不会发出update语句呢?
抱着种种疑问,我找到了hibernate的文件说明。在这里我截取重要理解部分
Hibernate defines and supports the following object states:
Transient - an object is transient if it has just been instantiated using the new operator, and it is not associated with a Hibernate Session. It has no persistent representation in the database and no identifier value has been assigned. Transient instances will be destroyed by the garbage collector if the application does not hold a reference anymore. Use the Hibernate Session to make an object persistent (and let Hibernate take care of the SQL statements that need to be executed for this transition).Persistent - a persistent instance has a representation in the database and an identifier value. It might just have been saved or loaded, however, it is by definition in the scope of a Session. Hibernate will detect any changes made to an object in persistent state and synchronize the state with the database when the unit of work completes. Developers do not execute manual UPDATE statements, or DELETE statements when an object should be made transient.
Detached - a detached instance is an object that has been persistent, but its Session has been closed. The reference to the object is still valid, of course, and the detached instance might even be modified in this state. A detached instance can be reattached to a new Session at a later point in time, making it (and all the modifications) persistent again.
意思就是:hibernate定义和支持对象的Transient (瞬时的)、persistent(持久的)、detached(分离的)状态。
当一个对象被new操作符创建实例的时候,并且与session没有任何的关联,就被称为transient状态的对象,这时这个对象没有持续化的标识,当这个对象没有被调用的时候,会被垃圾回收机制回收,但是通过与session的关联,能时其状态变为persistent状态。
persistent状态:处于persistent状态的对象在数据库中有persistent的标记和唯一的值,它处在session范围内,hibernate会自动检测处于当前状态的对象的变化,并且当执行完事务时,自动与数据库同步。
Detached 状态:处于当前状态的对象就是处于persistent状态的对象的session被关闭了。但是这个对象的引用仍然有效,而且这个状态能够通过与其他session关联变成persistent状态
下面我们来讨论一下对象状态之间的转换:
首先:transient -〉persistent
public void testSave_State(){
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
Person person=new Person();
person.setPname("ansel2");
session.save(person);
transaction.commit();
session.close();
}
运行结果:
Hibernate: select max(pid) from Person
Hibernate: insert into Person (pname, pid) values (?, ?)
由上可以说明,save()能使对象从transient to persistent
那么我们来测试一下,session.save(person);到底做了什么?为什么上面的测试没有session.update(person2);这句话又不会报错,但是又不会修改数据库里面的数据。
于是,我们在session.save(person);这一行,设置了一个断点,然后我们debug,进入界面后,刚刚进去的时候,窗口是这样的
我按下一步(F6)的时候,出现了一条select语句
这里应该不难理解,由于这里的主键生成器是increment,所以是由hibernate生成主键:把最大主键标号拿出来,然后再加一作为下一个主键。可是令人疑惑的就是,在这里并没有发出insert语句。那么我们再走一步看看,这时候发出了insert语句!
可是,既然是commit这一步发出的插入语句,那么我们在一开始测试的那个例子,也有commit这一步啊,为什么不可以呢?所以我认为,关键还是在session.save(person);上,在上面我们的引用英文的那段文字可以了解到,处于临时状态的对象,可以通过与session的关联变成持久化对象,那么就是说,session.save(person)这一步,是对象在与session关联。
下面我们来介绍session的一些方法:
public void testUpdate_State(){
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
//获取person对象
Person person=(Person) session.get(Person.class, 1L);
person.setPname("jeff hardy");
transaction.commit();
session.close();
}
我们使用session的get方法来获取对象,我们在session.get这一行设置断点。执行完这一步的时候,发出了一句select语句
可是,当执行完commit语句的时候,发出了update语句
我们在这段代码中,就是先获取到person对象,然后修改该对象的名字,然后提交事务,然后关闭session。
也就是说我们在获取person对象的之后,person就处于持久化状态了,经过修改属性,然后再到提交事务,在提交事务之后,hibernate会自动检测其所有的持久化对象有没有修改,如果有修改的话会让修改之后的对象与数据库同步。
session的clear方法:
@Test
public void testClear_State(){
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
//获取person对象
Person person=(Person) session.get(Person.class, 1L);
person.setPname("james");
session.clear();
transaction.commit();
session.close();
}
我在session.get()那一行设置了断点。直到执行完session.clear()的时候,都没有什么不同
然后我点下一步,一点点到执行完全部代码之后,还是没有什么异样。
加上前面几个例子的铺垫,我们可以知道,clear这个方法,是把当前session中的所有对象从持久化变成分离状态。
进阶测试1:
@Test
public void testClear_State(){
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
//获取person对象
Person person=(Person) session.get(Person.class, 1L);
session.clear();
person.setPname("big show");
session.update(person);
transaction.commit();
session.close();
}
我们这次依然在get方法设置断点,在执行了get方法之后,毫无意外的发出了select语句
执行完clear语句之后,并没有发出语句,而是把person这个对象从持久化状态变成了分离状态,此时,如果上面那段英文引用所说的,分离状态的对象的引用还是有效的
当执行完update语句的时候,还是没有任何动静
在执行完commit语句的时候,突然就发出了一条update语句!
这说明,update这个方法,把person从脱管 又变成了持久化状态!
进阶测试2:
@Test
public void testClear_State2(){
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
//获取person对象
Person person=(Person) session.get(Person.class, 1L);
session.clear();
transaction.commit();
session.close();
session=sessionFactory.openSession();
transaction=session.beginTransaction();
person.setPname("undertaker");
session.update(person);
transaction.commit();
session.close();
}
我们同样在get方法设置断点,然后又是毫无意外的发出了select语句
然后一直下一步,到session=sessionFactory.openSession();这一步运行完之后,有情况了!
session的id变了,翻了一下源代码,可以看到,session是new了一个新的
下一步之后,看到transaction也有新的id
执行完update语句之后,没有生产sql语句,在执行完commit语句之后,发出了update语句
由此可以看出,持久化状态是对于特定session来说的,当一个对象处于分离状态的时候,与另外一个session关联,新的session认为分离状态的对象与瞬时状态的对象没有什么区别。
在文章的结尾,用一副图来表示对象状态的转换
图中的evict方法我们没有介绍,该方法跟clear差不多,只不过clear是清空调用session中的所有对象,而evict是清空指定的对象。
503

被折叠的 条评论
为什么被折叠?



