Session.flush和session.evict

Session.flush和session.evict方法一起使用出现的问题

Flush:清空临时存储区Insertion,把缓存中的existsInDataBase=true,然后发出sql语句

Evict:清空缓存的EntiryEntires 中数据,但是不清空临时存储区Insertion的数据


Uuid生成策略下,在save以后,在Habernate的临时存储区Insertion和缓存中都会有数据,但是都没有提交到数据库existsInDataBase=false,这个时候如果调用evict,就会把缓存EntiryEntires 中的数据全部清除,但是却不会清除临时存储区中的内容。这个时候当执行commit的时候,session在临时存储区中发现了数据就会执行sql。然后会去缓存中更新缓存中的数据,把existsInDataBase=true.但是这个时候缓存中的数据已经被evict清除了。找不到existsInDataBase。这个时候Habernate会报线程安全异常。

这是因为在Session在清理缓存时,会去临时存储区Insertion取出数据进行insert操作后,需要更新EntiryEntires 中的existsInDataBase属性为TRUE,如果找不到这个属性,就会报异常,而我们的evict会把所有信息从EntiryEntires 清除了。所以找不到相关数据就抛异常


例如使用如下代码


//因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理

//不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false

session.save(user);


//将user对象从session中逐出,即session的EntityEntries属性中逐出

session.evict(user);


//无法成功提交,因为hibernate在清理缓存时,在session的insertions集合中取出user对象进行insert操作后需要更新entityEntries属性中的existsInDatabase为true,而我们采用evict已经将user从session的entityEntries中逐出了,所以找不到相关数据,无法更新,抛出异常

tx.commit();


解决上面问题的办法就是再执行save以后马上执行flush,这个flush会发出sql,同时将临时存储区Insertion清空。再执行evict会把EntiryEntires 中的数据清除。然后就执行commit的时候缓存中已经完全空了。所以不会有异常

实际代码如下

//因为user的主键生成策略采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理

//不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false

session.save(user);


//flush后hibernate会清理缓存,会将user对象保存到数据库中,将session中的insertions中的user对象

//清除,并且设置session中existsInDatebase的状态为true

session.flush();


//将user对象从session中逐出,即session的EntityEntries属性中逐出

session.evict(user);


//可以成功提交,因为hibernate在清理缓存时,在session的insertions集合中无法找到user对象

//所以就不会发出insert语句,也不会更新session中的existsInDatabase的状态

tx.commit();


Native生成策略下的evict

这个策略下,当执行save的时候就会把临时存储区Insertion清空,然后发出sql,然后把缓存的EntiryEntires的existsInDataBase属性为TRUE。

然后如果调用evict,又会把EntiryEntires中的数据清空,然后commit的时候不会执行任何信息,也没有异常,这种异常只在uuid生成策略下出现。


实际代码如下:


//因为user的主键生成策略为native,所以调用session.save后,将执行insert语句,返回有数据库生成的id

//纳入了session的管理,修改了session中existsInDatebase状态为true

//如果数据库的隔离级别设置为为提交读,那么我们可以看到save过的数据

session.save(user);


//将user对象从session中逐出,即session的EntityEntries属性中逐出

session.evict(user);


//可以成功提交,因为hibernate在清理缓存时,在session的insertions集合中无法找到user对象

//所以就不会发出insert语句,也不会更新session中的existsInDatabase的状态

tx.commit();

 

Hibernate执行insert,update,delete的顺序

在一个session线程中,如果存在多个insert,update,delete操作。Habernate会先把insert批量操作,然后是update,然后是delete。而不是按照我们代码的编写顺序进行执行。在某些情况下,这个特点会引起一些错误。

解决这个问题的办法就是在写好一个insert或者update以后,马上显示执行flush,马上执行这个save发出sql。就可以处理这个问题


就象下面这样

session = HibernateUtils.getSession();

tx = session.beginTransaction();


User3 user = new User3();

user.setId("003");

user.setName("张三");


session.save(user);


user.setName("王五");

session.update(user);

//注意这里,在sava和update以后执行flush

session.flush();


User3 user3 = new User3();

user3.setId("004");

user3.setName("李四");

session.save(user3);


//Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)

//Hibernate: update t_user3 set name=?, password=?, create_time=?, expire_time=? where user_id=?

//Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)

//因为我们在session.udpate(user)后执行了flush,所以在清理缓存时执行flush前的sql不会生成

//sql会按照我们的意愿执行

tx.commit();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值