hibernate零散经验整理

基本上都是以前看书后写下的笔记和实践操作的记录。

 

一、关于查询迭代函数list.iterator(),Query.iterate()的比较
用hibernate进行查询,然后对查询结果进行迭代,有两种实现方法:
1、List ls = session.createQuery("...").list();
Iterator iter = ls.iterator();
while(iter.hasNext()){
//...
Object obj = (Object)iter.next();//以对象形式返回结果
//...
}
2、Iterator iter = session.createQuery("...").iterate();
//createQuery()返回Query类型
      第一种查询方法list()函数,采用了一条语句直接查询了所有的结果;而第二种查询方法iterate(),则是先查询获得对象标识符(既是数据库主键),然后根据对象标识符,对每个标识符生成相应的查询语句,进行查询并实例化持久对象。

      另外如果开启了二级缓存,第二种方法iterate()函数可以利用二级缓存,而list ()却只能利用到一级缓存。

      对于海量信息的查询用两种方法都可以能会有内存溢出的情况出。但iterate()方法是对每一条记录进行了查询并实例化持久对象的,这样就可以对每次查询获得的结果进行缓存清理,从而解决内存溢出的问题。
while(iter.hasNext()){
Object obj = (Object)iter.next();
session.evict(obj);//一级清理
sessionFactory.evict(Object.class,obj.getId());//二级清理
}


二、JOIN FETCH连接查询的限制
      例如,A(a_id,name)和B(b_id,name,a_id)是一对多的关系,对应的HQL语句为:FROM A a JOIN FETCH a.B b那么返回的结果只会有左边的对象A的集合(返回的左边结果可能会有重复数据),而右边的关联对象B则同父对象访问时获取。
1、不能使用Query.iterate()来取得结果集,iterate()不允许使用FETCH连接
2、不能在分页方法中使用,因为返回的左边结果的数据可能会重复,就无法获取正确的记录数。
3、不能带WITH条件,否则会抛出异常QuerySyntaxException

 

三、有关乐观锁
      乐观锁的一般有两种实现方法:版本检查、时间截。
      1、版本检查要在对应的表添加版本号(version)字段(为整数类型),hibernate先会查询获取对应记录的verstion字段的值,在进行更新时,使用主键和先前所查得的version字段作为条件,并把version的值加1。如果主键和version对对应不到记录,更新失败,那么就会抛出异常。配置:<class optimistic-lock="version" ...><version name="vs" column="vs" type="java.lang.Integer"/></class>。使用版本检查在一个系统使用,而其他的系统也对该数据库进行操作,并且该系统没有使用版本检查,就会导致数据的不一致。
      2、时间截也是采用同样的过程也是一样的,只是把version字段设置为date类型,配置<class optimistic-lock="version" ...><timestamp name="vs" column="vs"/></class>,使用<timestap>节点一定要在<id>节点之后。由于时间的差异在并发线程同时读取和修改同一记录,可能导致数据的不一致,所以使用版本检查比较安全。
      3、如果是使用HQL语句进行更新,UPDATE语句是不会更新version字段的,需要使用versioned字段进行手工明确指定。update versioned A set name=:newName where name=:name

 

四、在批量更新和删除HQL语句中使用别名是无意义的
UPDATE A SET name=:newName WHERE name=:name和UPDATE A a SET a.name=:newName WHERE a.name=:name生成的SQL是完全一样的:update A set name=? where name=?。如果该成UPDATE A a SET a.name=:newName WHERE a.name=:name AND a.B.name="123"就会生成sql语句:update A set name=? where name=? and name="123",显然这个sql语句是错误的,并非所期望的结果。

 

五、HQL的DML及其insert

     DML的insert不支持insert into values形式的插入操作,也不支持多态。

     DML即为数据操纵语言,对数据库的数据进行操作,而对象关系映射管理的对象状态是存在于内存的,所以执行DML批量操作并不会清理一级缓存,为了不得到脏数据,在执行批量操作时调用session.evict()清空一级缓存。

 

六、相同与不同的持久对象
当是同一个session两次加载同一个主键记录时,生成的两个持久对象是相同的,可用==比较。
当是不同session各自加载同一个主键记录时,生成的两个持久对象是不同的。

 

七、性能提高
1、提高Hibernate启动速度。使用Configuration.addCatcheableFile()方法提高启动速度。
2、<class>节点的属性dynamic-update的默认值为false,对所有的属性进行更新。修改为true,这样就只对更改了的属性进行更新。
3、绕过hibernate,直接使用JDBC或者存储过程来批处理数据时,同过session获得Connection对象,session.connection(),最后还要清理一级缓存中的数据,session.clear(),并不需要调用connection.close()关闭数据库连接,session会在关闭时关闭。
4、在循环中进行批量操作,可以这样
for(int i=0; i<100000; i++){
//...
session.save(obj);
session.flush();
session.evict();
}
在上面已经提到,但性能提高并不大
可以这样做:
for(int i=0; i<100000; i++){
//...
session.save(obj);
if(i%20==0){
session.flush();
session.evict();
}
}
5、使用DML风格的批量操作。[UPDATE|DELETE] FROM? EntityName [WHERE conditions?],INSERT INTO EntityName properties_list SELETE selete_statement
6、在WEB应用中使用Open Sesion In View模式可以在MVC框架中实现延迟加载,安全关闭,避免频繁创建销毁。

 

八、有关查询缓存
      查询缓存是依赖于二级缓存的,查询结果较小,查询条件较稳定时方可以用查询缓存。
      要在代码声明使用查询缓存,并设置区域,query.setCacheable(true);query.setCatcheRegion("abc");在对查询更改后,必须使用essionFactory.evictQueries("abc");清除查询缓存,否则会得到脏数据。
      二级缓存的实现是以查询的HQL和查询参数作为key保持的,如果先后两个查询语句条件相近,查得的结果集相同或相近,第二个查询的部分结果集并不是在第一个查询结果集查找到的,而是重新全部从数据库加载。
       例如:from A a where a.age>44和from A a where a.age>42,两个查询语句条件相近,第一条查询结果集是第二条查询结果集的一部分,但是第二条查询部分结果集并不是从第一条查询结果集来的。
      可以用OSCache控制缓存失效。

你可能感兴趣的:(sql,Hibernate,mvc,jdbc,配置管理)