第七章 Hibernate性能优化
第七章 Hibernate性能优化
7.1 映射一对一关联
7.7.1按照外键映射
用<many-to-one>来映射Emp表类的dept属性
例:<many-to-one name="dept"
column="DEPTNO"
class="com.entity.Dpet"
cascade="all"
unique="true"
/>
用<one-to-one>来映射dept 表的emps属性
例:<one-to-one
name="emps"
class="com.entity.Emp"
property="emps"//表明通过dept的emps属性建立了从dept到emps对象的关联
/>
7.1.2 按照主键映射
用<one-to-one>元素来映射EMp类的dept属性
<one-to-one
name="dept"
class="com.entity.Dpet"
constrained="true"//此属性为true,表明以emp表的主键同时作为外键参照Dept表的主键
/>
在Dept.hbm.xml下必须使用foreign主键生成策略
<id name="userid" type="java.lang.Integer">
<column name="USERID" precision="22" scale="0" />
<generator class="foreign">
<param name="property">dept</param>
</generator>
</id>
7.2 组件映射
对应数据库的一张表建立两个实体类,各包含一部分属性,并相互关联,且建立一个映射文件
例:
<class name="com.entity.Empinfo" table="EMPINFO" schema="SCOTT">
<id name="eid" type="java.lang.Integer">
<column name="EID" precision="22" scale="0" />
<generator class="assigned" />
</id>
<property name="ename" type="java.lang.String" column="ENAME"></property>
<component name="emphome" class="com.entity.EmpHomeAddress" >//name设定被映射的持久化类的属性名,class为name的类型
<parent name="empinfo"/>
<property name="ehomestreet" type="java.lang.String" column="EHOMESTAREET"></property>
<property name="ehomecity" type="java.lang.String" column="EHOMECITY"></property>
。。。
</component>
</class>
7.3 Hibernate缓存
7.3.1 分类
1)一级缓存
session内的缓存即一级缓存,位于缓存中的对象称为持久化对象,它和数据库的相关记录对应。
当应用调用save(),update(),saveOrUpdate(),load()或get()方法,以及query查询接口的list()和iterate()方法时
如果session缓存中还不存在相应对象,Hibernate就会吧对象加入到一级缓存中。
session缓存的两大作业:
1、减少范围数据库的频率
2、保证数据库中的相关记录与缓存中的相应对象同步
session的两个管理缓存的方法:
1、evict(Object o);从缓存中清除指定的持久化对象
2、clear();清空缓存中的所持久化对象
flush()用于强制进行从缓存到数据库的同步
2)二级缓存(进程范围或集群范围)
二级缓存可以被所有的session共享,起生命周期和SessionFactory相当
二级缓存可配置插件如:EHCache、OSCache、SwarmCache、JBossCache
配置二级缓存的步骤:
1、选择相应插件(ehcache-1.2.3.jar/ehcache.xml)
2、选择需要二级缓存的持久化类,设置它的二级缓存的并发访问策略
例:1)将ehcache.xml放在项目src文件夹下
例:
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
2)开启二级缓存
<property name="hibernate.cache.use_second_level_cache">true</property>
3)指定缓存供应商
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
4)指定二级缓存的持久化类,修改持久化类的映射文件
<class name="com.entity.Dept" lazy="false" table="DEPT">
<!-- 二级缓存 -->
<cache usage="read-write" region="" include="all"/>
<!--
usage 是必须的,指定并发访问策略取值为Transaction,(事务缓存),
read-write(读写缓存),nonstrict-read-write(非严格读写缓存)或read-only(只读缓存)
region属性可选,默认为类或集合的名称
include属性可选,取值为non-lazy,all
-->
<id name="deptno" type="java.lang.Integer">
<column name="DEPTNO"/>
<generator class="native">
<param name="sequence">seq_dept</param>
</generator>
</id>
<property name="dname" type="java.lang.String">
<column name="DNAME" length="14" />
</property>
</class>
注:配置二级缓存所需插件(可选择新版本)
commons-logging-1.0.4.jar
ehcache-1.2.3.jar
3)查询缓存(针对查询的缓存)
查询缓存适用步骤:
1)在Hibernate.cfg.xml中开启查询
2)在程序中使用缓存
如:query.setCacheable(true).list();
范围
1)事务范围:每个事务都有自己的缓存,缓存内数据不会被多个事务并发访问
2)进程范围:进程内的所有事务共享缓存,进程结束,缓存结束生命周期
3)集群范围:被一个或多个机器上的多个进程共享二级缓存也可以作为集群范围的缓存
7.4 HQL的连接查询
HQL支持的连接查询
内连接 inner join 或 join
迫切内连接 inner join fetch或join fetch
左外链接 left outer join或left join
迫切左外链接 left outer joinright outer join 或 right joinleft join fetch
右外连接 right outer join 或 right join
1、内连接
语法:
from entity inner join [fetch] entity.property
例:List<Object[]> list=session.createQuery("from Dept d inner join d.emps").list();
for(Object[] obj:list){
System.out.println(obj[0]+"~~~~"+obj[1]);
}
2、隐式内连接
例:List<Emp> emplist=session.createQuery("from Emp e where e.dept.dname='开发部'").list();
for(Emp emp:emplist){
System.out.println(emp.getEname()+"~~~~"+emp.getEname());
}
3、外连接
语法: 左
from entity lef join [fetch] entity.property
右
from entity right join entity.property
4、交叉连接
查询性能优化
1、Hibernate优化性能
1)使用迫切外链接或迫切内连接查询策略,查询缓存等方式,减少select查询语句,降低访问数据库的频率
2) 使用延迟查询策略避免加载多余的数据
3)使用Query接口的iterate()方法减少select语句中的字段降低访问数据库的数据量
2、HQL优化
1)避免or的使用不当
2)避免使用not
3)避免使用like特殊形式
4)避免使用having子句
5)避免使用distinct
6)所有在以下情况会失效
a、只有第字段使用函数,索引将不起效,如substring(aa,1,2)="xx"
b、只有对字段进行计算,索引将不起效,如price+10
7.5 批量处理数据
1、使用HQL进行批量操作
1、批量插入数据
语法:
insert into entity properties select_statement
例:Dept.hbm.xml配置
<id name="deptno" type="java.lang.Integer">
<column name="DEPTNO"/>
<generator class="native">
<param name="sequence">seq_dept</param>
</generator>
</id>
测试代码:
String hql="insert into Dept(dname) select d.dname || d.deptno from Dept d where d.deptno>0";
session.createQuery(hql).executeUpdate();
2、批量更新数据
语法:
update entity set propertie=values
例:String hql="update Dept set loc=:loc";
session.createQuery(hql).setString("loc", "东一区").executeUpdate();
2、批量删除数据
语法:
delete entit
例:String hql="delete Dept d where d.deptno>:deptno";
session.createQuery(hql).setInteger("deptno", new Integer(30)).executeUpdate();
2、使用JDBC API进行批量操作
例:Work work=new Work() {
Connection connection=null;
@Override
public void execute(Connection arg0) throws SQLException {
String sql="update DEPT set LOC=? where DEPTNO<?";
PreparedStatement ps=connection.prepareStatement(sql);
ps.setString(1, "西一区");
ps.setInt(2, 26);
ps.executeUpdate();
}
};
session.doWork(work);
3、使用session进行批量操作
。。。
三种批处理对比
JDBC API批量操作最灵活
HQL批量操作方式可跨数据库
session批处理操作把关数据加载到内存后再进行操作