程序通过Hibernare来加载保存修改删除或者是更新数据的时候,可能会导致数据库层的一些触发器引起相关的操作,也可能会引发Hibernare拦截器的一些相关操作。
我们知道Hibernare按照常规的方式进行批量的操作会导致大量的持久化对象加载到内存当中,从而消耗大量的内存空间,极有可能会导致内存的空间的不足而产生错误。
数据库中的出发器在与Hibernare协同工作的时候可能会带来许多负面的问题:
1: 触发器导致Session的缓存中的持久化对象与数据库中的对应数据出现不一致的现象
2: Session的update可能会盲目的触发或者说是激活触发器
先简述下 1: 触发器导致Session的缓存中的持久化对象与数据库中的对应数据出现不一致的现象
下面举个简单的例子和解决这类问题的解决方案:
假设有一个这样的bean类Customer
文件Custome.java
Customer.hbm.xml
下面是测试类:
控制台输出信息为:
测试testDirect()时控制台输出的信息:
drop table if exists CUSTOMERS
create table CUSTOMERS (ID bigint not null, NAME varchar(15), REGISTER_DATE datetime, primary key (ID))
Hibernate: select max(ID) from CUSTOMERS
1->RegisterDate: Sat Jul 10 21:58:25 CST 2010
2->customer.getRegisterDate(): Sat Jul 10 21:58:25 CST 2010
两者引用同一地址(对象)? true
Hibernate: insert into CUSTOMERS (NAME, ID) values (?, ?)
测试testFlush()时控制台输出的信息:
测试testFlushAndRefresh()时控制台输出的信息:
查询mysql 获取的信息(以上的每个方法 都是如下结果)
mysql> select * from customers;
+----+---------+---------------+
| ID | NAME | REGISTER_DATE |
+----+---------+---------------+
| 1 | macower | NULL |
+----+---------+---------------+
1 row in set (0.00 sec)
很明显Session并没有将REGISTER_DATE字段进行赋值。直接保存或者清理缓存时仍然会发现数据库中的记录和Session缓存的记录存在不一致的情况,只要当进行refresh()迫使Session的缓存和数据库同步的时候才能保证在缓存中得到的数据是真实的数据。
当然,当我们将 REGISTER_DATE在Hibernare一端插入空值,在mysql一端直接写sql语句或者其他程序调用jdbc将REGISTER_DATE赋值的时候Hibernare 的Session在默认情况下是探测不到这种变化的因此,假设我们在后续中要用到 Session保存的数据我们就需要进行 缓存的清理和refres()以此来同步数据库与Session的缓存,从而才能保证数据的一致性,当然假设在后续阶段我们在当前的缓存中不会用到这个持久化的对象,此时我们也就没了必要在此处进行数据库的同步从而在一定程度上提高了一定的性能。当开启另外一个Session时候我们一样的可以查询到真实的数据。
接下来分析下 2: Session的update可能会盲目的触发或者说是激活触发器
假设在数据库中定义了有update引起的事件激活了触发器,那么我们就需要额外的谨慎的使用update和saveOrupdate()方法。
我们知道这两个对象都够将一个游离的对象重新和Session进行关联,由于Session的缓存中还不存在这个对象的快照(说白了就是我们在j2se中所讲述的深拷贝而来的对象,在Hibernare中有一个这样的方法叫做deepCopy()),因此Session就无法判断是游离对象是否与数据库的保持一致(检测的时候是拿当前对象与快照进行比对,比对的时候用的equals方法),所以Session为了保险起见,不管是游离对象的属性是否发生变化都会执行update语句,而此时执行update的时候就会激活相应的触发器,当数据并无变化的时候(或者说是游离对象的属性和数据库中的一致),显然此时的update就是多余的,那么此时激活触发器就是毫无意义,甚至带来危害。所以我们需要考虑到这种情况,幸好Hibernare提供了这个问题的解决方案。
就是在<class>标签 加一个select-before-update='true' 就行了,在Hibernate session浅见(1)中讲述了 在查询之前Hibernate会进行同步刷新数据库以此来保证数据的一致性。这样配置以后会执行一条select语句来获取这个对象的最新数据,然后进行比对,在不一致的情况下才会执行update语句,这样就避免了执行多余的update语句,以及盲目的激活相关的触发器。
总之Session是非常重要也是非常关键的一个部分,设计到整个程序中最关键的东西---数据,因此需要对其进行格外的注意,理解了Session才能开始理解Hibernare的基本设计思想,也才能保证数据的安全和一致。总之Hibernare的Session是Hibernare设计的一个杰作,需要我们认真的去体会和学习。