hibernate优化
session控制
为了避免session创建的开销,需要对session的创建进行控制
当前行为:
使用ThreadLocal的方式控制session的创建
使用filter的方式创建和关闭session
尚未配置filter
事务控制
针对hibernate由三种dao操作 find save flush
find即查询不需要开事务,所以可以考虑针对查询不使用事务控制
针对saveOrUpdate使用事务
现在事务提交是在filter结束的时候去做
但有一些action中是不需要事务的,频繁开关事务可能会带来一定的系统开销
当前测试使用和不使用事务进行查询测试结果(根据ID查询记录100次时间比较)
不开事务 421ms
打开事务 516ms
事务的开关最好限定在方法内部,可以考虑在service方法中开关事务,可以避免这个问题
session关闭和事务提交的时候,hibernate会主动调用flush方法进行数据库同步
所以在当前项目中不需要关心flush方法
事务实现选用和配置
使用jdbc事务控制
不选用jta作为事务的实现
放弃理由
当前测试服务器tomcat本身仅仅是个web server,并不支持jta
配置hibernate属性信息
hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
net.sf.hibernate.transaction.JDBCTransactionFactory
jta的好处
JTA提供了跨Session的事务管理能力
为以后扩展留下了选择空间
实现
单一的增删改操作不需要调用session.beginTransaction()等方法
针对多条记录的修改使用下面的方式调用api
UserTransaction ut = (UserTransaction)(new InitialContext().lookup("java:comp/UserTransaction"));
ut.begin();
//.....
ut.commit();
使用下面的方式也可以同样实现事务控制,但因为hibernate内部同样调用上面的api实现
处于节省资源的想法,不建议使用
Transaction tx = session.beginTransaction();
tx.commit();
以后可以考虑使用spring的aop实现替换当前实现
在tomcat中的配置
<Resource name="UserTransaction" auth="Container" type="javax.transaction.UserTransaction"/>
<ResourceParams name="UserTransaction">
<parameter>
<name>factory</name>
<value>org.objectweb.jotm.UserTransactionFactory</value>
</parameter>
<parameter>
<name>jotm.timeout</name>
<value>60</value>
</parameter>
</ResourceParams>
分页控制
通过criteria. setFirstResult/setMaxResults方法可以限制一次查询返回的记录范围
延迟加载
lazy_load
所有有关数据关联(一对多,多对多等)的映射都需要指定延迟加载
因为当前系统的session关闭是在filter里面做的,所以不需要控制关联对象的加载
在特殊的情况下,比如session关闭后获取关联对象
可以在session关闭前调用Hibernate.initialize()API获取关联对象
缓存选用及配置管理
当前选用EHCache作为第二层的缓存(第一层为数据库缓存)
由于EHCache不支持分布式,所以将来可以考虑使用jgroup实现分布式
针对系统内大部分的dao操作使用只读(read)方式进行缓存
需要写入的部署在不同的机器上解决多个jvm上数据不一致的问题
EHCache配置
首先配置hibernate缓存provider class属性
hibernate.cache.provider_class net.sf.ehcache.hibernate.Provider
配置ehcahe配置文件
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000" //Cache中最大允许保存的数据数量
eternal="false" //Cache中数据是否为常量
timeToIdleSeconds="120" //缓存数据钝化时间
timeToLiveSeconds="120" //缓存数据的生存时间
overflowToDisk="true" //内存不足时,是否启用磁盘缓存
/>
</ehcache>
在hibernate映射文件中指定各个映射实体的Cache策略
<cache usage="read-write"/>
<cache usage="read-only"/>
配置好Cache之后,Hibernate在运行期会自动应用Cache机制
对于查询方法的选用策略
Query.list();
通过一条sql语句返回所有对象
Query.iterate();
而iterate方法,则是首先通过一条Select SQL获取所有符合查询条件的记录的id
再对这个id集合进行循环操作,通过单独的Select SQL取出每个id所对应的记录
之后填入POJO中返回。
但list方法不会从缓存中读取数据
而iterator方法在返回id集合后,针对每一条记录会先到缓存中读取数据
综合以上,当前系统使用原则
少量的数据和不频繁访问的数据使用list方法
频繁访问的数据使用iterator方法
数据库连接池配置和管理
出于通用的原则选用dbcp
hibernate中的配置
###################################
### Apache DBCP Connection Pool ###
###################################
## connection pool
#hibernate.dbcp.maxActive 100
#hibernate.dbcp.whenExhaustedAction 1
#hibernate.dbcp.maxWait 120000
#hibernate.dbcp.maxIdle 10
## prepared statement cache
#hibernate.dbcp.ps.maxActive 100
#hibernate.dbcp.ps.whenExhaustedAction 1
#hibernate.dbcp.ps.maxWait 120000
#hibernate.dbcp.ps.maxIdle 10
其他配置
hibernate.cache.use_query_cache
cache.use_minimal_puts false
其他问题
当获取大量关联数据的时候,需要指定关联集合属性 (解决N+1 Select问题)
batch-size (可选,默认是1) 指定一个用于根据标识符抓取实例时使用的"batch size"(批次抓取数量)
可设置为10
对于一些统计查询,尽可能使用hql,而不要依赖于映射进行获取
对于代码级别的特殊查询,通过设置FetchMode提高效率
使用绑定变量
在查询中,使用占位符号: 替换非常量值,在查询中使用命名参数
因为query是可以缓存的,所以使用命名参数的方式可以提升查询效率