Whenever you pass an object to save()
, update()
or saveOrUpdate()
, and whenever you retrieve an object usingload()
,get()
,list()
,iterate()
or scroll()
, that object is added to the internal cache of theSession
.
When flush()
is subsequently called, the state of that object will be synchronized with the database. If you do not want this synchronization to occur, or if you are processing a huge number of objects and need to manage memory efficiently, the evict()
method can be used to remove the object and its collections from the first-level cache.
Example 21.9. Explcitly evicting a cached instance from the first level cache usingSession.evict()
while ( cats.next() ) {
Cat cat = (Cat) cats.get(0);
doSomethingWithACat(cat);
sess.evict(cat);
}
Session
also provides a
contains()
method to determine if an instance belongs to the session cache.
To evict all objects from the session cache, call Session.clear()
flush
void flush() throws HibernateException
-
Force this session to flush. Must be called at the end of a unit of work, before committing the transaction and closing the session (depending on
flush-mode
,Transaction.commit()
calls this method).Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory.
-
-
-
Throws:
-
HibernateException
- Indicates problems flushing the session or talking to the database.
-
clear
void clear()
- Completely clear the session. Evict all loaded instances and cancel all pending saves, updates and deletions. Do not close open iterators or instances of ScrollableResults.
@Test
public void save() {
ApplicationContext actionContext=new ClassPathXmlApplicationContext("beans.xml");
SessionFactory sf =(SessionFactory) actionContext.getBean("mySessionFactory");
Session session = sf.openSession();
Transaction transaction = session.beginTransaction();
Student student = new Student();
student.setId(Long.valueOf(3));
student.setName("aa");
session.save(student);
//session.clear(); //加上则清空session session.flush(); // 与数据库同步 transaction.commit();
session.close();
}
由于session caches的原因,
public void upload(){
ApplicationContext actionContext=new ClassPathXmlApplicationContext("beans.xml");
SessionFactory sf =(SessionFactory) actionContext.getBean("mySessionFactory");
Session session = sf.openSession();
Transaction transaction = session.beginTransaction();
Student student = (Student) session.createQuery(" from Student s where s.id = 1").uniqueResult(); //1句
Student student2 = (Student) session.createQuery(" from Student s where s.id = 1").uniqueResult(); //2句
session.clear(); //3句
Student student3 = (Student) session.createQuery(" from Student s where s.id = 1").uniqueResult(); //4句
transaction.commit();
session.close();
}
因为"1句"查出的student在session里面
所以如果1,2句之间我在数据库update id=1的student的名字
update student s set s.name='sl' where s.id=1;
commit;
二句是查不到的,确切的说是没检查name列,而是只检查了id主键,hibernate一看该id为1的student的对象在缓存里面,就不关心其他属性了,咱们看下hibernate生成的sql就明白了
Hibernate: select student0_.id as id3_, student0_.name as name3_ from student student0_ where student0_.id=1
21:04:23,166 TRACE BasicExtractor:71 - found [1] as column [id3_]
21:04:23,182 TRACE BasicExtractor:71 - found [dd] as column [name3_]
Hibernate: select student0_.id as id3_, student0_.name as name3_ from student student0_ where student0_.id=1
21:05:34,788 TRACE BasicExtractor:71 - found [1] as column [id3_]
可以看到只查询了id就没再查询
当我用3句情况session里面的对象之后,由于session里面没有此id的student的对象,hibernate会重新查询id为1的所有student表中的所有列,然后再把封装的student3对象放到session里
下面是hibernate在执行"4句"时生成的sql语句
Hibernate: select student0_.id as id3_, student0_.name as name3_ from student student0_ where student0_.id=1
21:05:50,966 TRACE BasicExtractor:71 - found [1] as column [id3_]
21:05:50,966 TRACE BasicExtractor:71 - found [sl] as column [name3_]
可见2个列都查询出来了,而我们update的"s1"的name列也查出来了
所以虽然@transactional可以指定isolation=READ_COMMITTED
但是要先清除session里面该对象,再次查询该对象才能查询出其他transaction更改commit该对象的数据,即出现幻读
关于幻读可以看http://blog.csdn.net/wyxz126/article/details/8751926