Hibernate与数据库触发器协同工作

 

数据库触发器是数据库的一种监听机制,这种机制会监视数据库中的某种特定的操作,当这种操作发生时,触发器就会执行,并且会完成一些特定的逻辑,在数据库中能够激发触发器的操作有:insert,update,delete三种,当这三种操作发生在一条记录或者某个特殊字段上,如果在该记录或者该字段上有触发器,那么触发器便会被激发执行。但是当Hibernate与触发器协同执行时,会造成两个问题。

第一:触发器使得Session中的数据与数据库中的数据不一致;
第二:Sessionupdate操作会盲目触发触发器;
下面我们就分别讨论这两个问题的原因和解决办法。
A、触发器使得Session中的数据与数据库中的数据不一致:
造成这个问题的根本原因,是因为触发器对数据库的操作对Hibernate Session是透明的,触发器对数据库的某些更改,无法被Session感知,因此无法被同步到缓存之中,我们看下面的代码,假设在数库中的user表中的registerd_time字段上设置了一个触发器,当有新的user对象被保存时,数据库就自动将数据库当前时间之值,插入到该字段中:
tx=session.beginTransaction();
session.save(user);
System.out.println(user.getRegisterdTime());
tx.commit();
当执行完save()操作后,打印注册时间字段,这时发现该字段值为空。这是因为此时真正的insert SQL语句还没有真正执行,所以触发器还没有被执行。我们修改上面的代码如下:
tx=session.beginTransaction();
session.save(user);
session.flush();
System.out.println(user.getRegisterdTime());
user=session.load(User.class,”1”);
System.out.println(user.getRegisterdTime());
tx.commit();
我们增加了强制清空缓存并且强制提交的操作,这个操作会激发insert SQL语句的执行,并且激发触发器的执行,此时打印注册时间发现已经变成了数据库当前时间,但是当再次加载刚刚被保存的user对象后打印注册时间,发现还是空值,这是因为由于触发器会自动填写注册时间值,所以在构造user对象时没有设置该属性值,这个属性值被触发器在数据库端自动设置,但是由于触发器对数据库的操作对Hibernate Session是透明的,触发器对该字段的更改,无法被Session感知,所以在缓存中该字段仍然是null,当加载这个对象时,由于save操作此对象被置于缓存中,所以load方法从缓存中将该对象获得,当调用user.getRegisterdTime()时会得到缓存中的空值。那么我们怎样才能避免出现这个问题呢?看下面的代码:
tx=session.beginTransaction();
session.save(user);
session.flush();
System.out.println(user.getRegisterdTime());
session.refresh(user);
user=session.load(User.class,”1”);
System.out.println(user.getRegisterdTime());
tx.commit();
这里我们调用了refresh方法,该方法会重新从数据库中加载刚刚被保存的user对象到缓存中,这样就同步了缓存与数据库数据,所以当再次调用load方法时,从缓存中获得的数据就会同数据库中的数据保持同步,所以再次打印注册时间时,就会打印出数据库当前时间。
B、Sessionupdate操作会盲目触发触发器:
如果在数据库中定义了针对update操作的触发器,那么必须要谨慎的使用SessionupdatesaveOrUpdate(),因为这两个方法能够使一个游离对象再次变成持久化对象,因为有可能在Session的缓存中,还不存在要更新对象的快照,所以就无法判断游离对象的属性是否与数据库中保持一致,为了保险起见,Hibernate默认的操作是,不管实体对象的属性是否发生了变化,都要发起一条update SQL语句的执行,来同步实体对象属性值与数据库字段值,即同步数据库字段值与缓存数据属性值。这时如果对应的数据库表中有update触发器,那么就会触发该触发器的执行,但是如果此时这个对象的属性值并没有发生改变,也就是说实体对象的属性值与数据库中对应表的对应记录保持一致,那么,这个触发器的执行就是没有必要的,此时Sessionupdate操作就触发了多余的触发器。那么我们怎样才能避免这个问题呢?我们可以开启实体对象配置文件中<class>元素的,“select-before-update”属性选项,我们可以如下进行配置:
<class name=”com.neusoft.entity.User” table=”user” select-before-update=”true”>
   ……
</class>
这时当执行Session.update()/saveOrUpdate()操作时,会首先执行select SQL,查询出该对象所有
属性值,然后与要进行更新的实体对象属性值进行比较,如果都相同,那么就不会执行update
作,这时就不会由于执行了没必要的update SQL语句,而激发多余的update触发器操作了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值