1.Session 级别的缓存,它同session邦定。它的生命周期和session相同。Session消毁,它也同时消毁;管理一级缓存,一级缓存无法取消,用两个方法管理,clear(),evict()
2.两个session 不能共享一级缓存,因它会伴随session的生命周期的创建和消毁;
3.Session缓存是实体级别的缓存
,就是只有在查询对象级别的时候才使用
,如果使用HQL和SQL是查询属性级别
的,是不使用一级缓存的!切记!!!!
4.iterate 查询使用缓存,会发出查询Id的SQL和HQL语句,但不会发出查实体的,它查询完会把相应的实体放到缓存里边,一些实体查询如果缓存里边有,就从缓存中查询,但还是会发出查询id的SQL和HQL语句。如果缓存中没有它会数据库中查询,然后将查询到的实体一个一个放到缓存中去,所以会有N+1问题出现。
3.Session缓存是实体级别的缓存
,就是只有在查询对象级别的时候才使用
,如果使用HQL和SQL是查询属性级别
的,是不使用一级缓存的!切记!!!!
4.iterate 查询使用缓存,会发出查询Id的SQL和HQL语句,但不会发出查实体的,它查询完会把相应的实体放到缓存里边,一些实体查询如果缓存里边有,就从缓存中查询,但还是会发出查询id的SQL和HQL语句。如果缓存中没有它会数据库中查询,然后将查询到的实体一个一个放到缓存中去,所以会有N+1问题出现。
每一个Hibernate Session实例和一个数据库事务绑定通常将每一个Hibernate Session实例和一个数据处理库事务绑定就是说,每执行一个数据库事务(操作),都应该先创建一个新的Hibernate Session实例.
如果事务执行中出现异常,应该撤消事务.不论事务执行成功与否,最后都应该调用Session的close()方法,从而释放Hibernate Session实例占用的资源.
如何获得Session对象
首先创建SessionFactory对
象,如果访问多个数据源时,则应该产生多个SessionFactory;
象,如果访问多个数据源时,则应该产生多个SessionFactory;
但是仅仅为了服务与某个请求时,不要创建一个新的SessionFactory,因为创建SessionFactory需要消耗大量的资源
,然后根据SessionFactory再创建Session对象
,然后根据SessionFactory再创建Session对象
Session session=factory.openSession();
Transaction ts =
null
;
try
{
ts=session.beginTransaction();
//开始一个事务
................... //执行事务
ts.commit(); //提交事务
}
catch
(HibernateException e) {
//如果出现异常就撤销事务
if
(ts!=null
){
ts.rollback(); //回滚事务
}
e.printStackTrace();
}
finally
{
session.close();//不管事务执行成功与否,最后都关闭Session并且放在finally中以提高安全性
}
Transaction ts =
null
;
try
{
ts=session.beginTransaction();
//开始一个事务
................... //执行事务
ts.commit(); //提交事务
}
catch
(HibernateException e) {
//如果出现异常就撤销事务
if
(ts!=null
){
ts.rollback(); //回滚事务
}
e.printStackTrace();
}
finally
{
session.close();//不管事务执行成功与否,最后都关闭Session并且放在finally中以提高安全性
}
下面我们重点看一下Session级的缓存
Hibernate
缓存分为二级,第一级存放于
session
中称为一级缓存,默认带有且不能卸载
缓存分为二级,第一级存放于
session
中称为一级缓存,默认带有且不能卸载
因为
Session
的生命期往往很短,存在于
Session
内部的最快缓存的生命期当然也很短,
所以第一级缓存的命中率是很低的
。其对系统性能的改善也是很有限的。当然,这个
Session
内部缓存的主要作用是保持
Session
内部数据状态同步
。并非是
hibernate
为了大幅提高系统性能所提供的。
Session
的生命期往往很短,存在于
Session
内部的最快缓存的生命期当然也很短,
所以第一级缓存的命中率是很低的
。其对系统性能的改善也是很有限的。当然,这个
Session
内部缓存的主要作用是保持
Session
内部数据状态同步
。并非是
hibernate
为了大幅提高系统性能所提供的。
为了提高使用
hibernate
的性能,除了常规的一些需要注意的方法比如:
使用延迟加载、迫切外连接、查询过滤等以外,还需要配置
hibernate
的二级缓存。其对系统整体性能的改善往往具有立竿见影的效果。.
hibernate
的性能,除了常规的一些需要注意的方法比如:
使用延迟加载、迫切外连接、查询过滤等以外,还需要配置
hibernate
的二级缓存。其对系统整体性能的改善往往具有立竿见影的效果。.
应用
Hibernate的一级缓存是由Session提供的,因此它只存在于Session的生命周期中,当程序调用save(),update(),saveorupdate()等方法 及调用查询接口list,filter,iterate时,如session缓存中还不存在相应的对象,Hibernate会把该对象加入到一级缓存中
,
当Session关闭的时候该Session所管理的一级缓存也会立即被清除
Hibernate的一级缓存是Session所内置的,不能被卸载,也不能进行任何配置
一级缓存采用的是key-value的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。所以说,一级缓存是以实体对象为单位进行存储
的,在访问的时候使用的是主关键字ID
虽然,Hibernate对一级缓存使用的是自动维护的功能,没有提供任何配置功能,但是可以通过Session中所提供的方法来对一级缓存的管理进行手工干预。Session中所提供的干预方法包括以下两种
●evict() :用于将某个对象从Session的一级缓存中清除
evict()方法适用于以下二种情况:
1)不需要该对象进行同步的数据更新
2)在批量进行更新与删除时,当更新删除每一个对象后,要释对此对象所占用的内存.
●clear() :用于将一级缓存中的所有对象全部清除。
在进行大批量数据一次性更新的时候,会占用非常多的内存来缓存被更新的对象。这时就应该阶段性地调用clear()方法来清空一级缓存中的对象,控制一级缓存的大小,以避免产生内存溢出的情况。
Hibernate大批量更新时缓存的处理方法:
(假设我们user表的age有5000条大于0的记录,)
,
当Session关闭的时候该Session所管理的一级缓存也会立即被清除
Hibernate的一级缓存是Session所内置的,不能被卸载,也不能进行任何配置
一级缓存采用的是key-value的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。所以说,一级缓存是以实体对象为单位进行存储
的,在访问的时候使用的是主关键字ID
虽然,Hibernate对一级缓存使用的是自动维护的功能,没有提供任何配置功能,但是可以通过Session中所提供的方法来对一级缓存的管理进行手工干预。Session中所提供的干预方法包括以下两种
●evict() :用于将某个对象从Session的一级缓存中清除
evict()方法适用于以下二种情况:
1)不需要该对象进行同步的数据更新
2)在批量进行更新与删除时,当更新删除每一个对象后,要释对此对象所占用的内存.
●clear() :用于将一级缓存中的所有对象全部清除。
在进行大批量数据一次性更新的时候,会占用非常多的内存来缓存被更新的对象。这时就应该阶段性地调用clear()方法来清空一级缓存中的对象,控制一级缓存的大小,以避免产生内存溢出的情况。
Hibernate大批量更新时缓存的处理方法:
(假设我们user表的age有5000条大于0的记录,)
Session session =SessionFactory.openSession();
Transaction
tx =session.beginTransaction();
Itertaor users=session.find("from
User
u
where
u.age>0").itertaor();//HSL语句就不做解释了
while
(user
.hasNext()){
User
user
=(User
)users.next();
user
.setAge(user
.getAge()+1);
//将本批插入的对象立即写入数据库并释放内存
session.flush();
session.clear();
}
tx.commit
();
session.close
();
Transaction
tx =session.beginTransaction();
Itertaor users=session.find("from
User
u
where
u.age>0").itertaor();//HSL语句就不做解释了
while
(user
.hasNext()){
User
user
=(User
)users.next();
user
.setAge(user
.getAge()+1);
//将本批插入的对象立即写入数据库并释放内存
session.flush();
session.clear();
}
tx.commit
();
session.close
();
用Hibernate处理大批数据时..都必须先执行5000次的update语句,然后才能更新5000个user 对象..
这样就影响到了操作上的性能....在项目当我们遇到性能与空间的问题时,,,要以性能为主..这也就是说要牺牲空间
所以程序最好跳过Hibernate API 而直接通过JDBC API来执来...
我们改一下上面的代码:
Session session=SessionFactory.openSession();
Transaction
tx =session.beginTransaction();
Connection conn =session.connection();
PreparedStatement pstmt = conn.prepareStatement("update
users
set
age=age+1 "+"where
age >0");
pstmt.executeUpdate();
tx.commit
();
Transaction
tx =session.beginTransaction();
Connection conn =session.connection();
PreparedStatement pstmt = conn.prepareStatement("update
users
set
age=age+1 "+"where
age >0");
pstmt.executeUpdate();
tx.commit
();
虽说这是通过JDBC API.但本质上还是通过Hibernater Transaction的事务这个接口来声明事务的边界的...
其实最好的解决方法就是以创建存储过程,,用底层的数据库运行..这样性能好,速度快....
我就简单的以Oracle数据库为例子.创建一个名为UserUpdate的存储过程...然后在程序中进行调用...
UserUpdate的存储过程代码:
create
or
replace
procadure UserUpdate(u_age
in
number)
as
begin
update
users
set
age=age+1
where
age>u_age;
end
;
create
or
replace
procadure UserUpdate(u_age
in
number)
as
begin
update
users
set
age=age+1
where
age>u_age;
end
;
下面的是在程序中如何调用我们命名的存储过程
Session session =SessionFactory.openSession();
Transaction tx =session.beginTransaction();
Connection conn=session.connection();
String str="{call UserUpdate(?)}"
;
CallableStatement cstmt= conn.prepareCall(str);
cstmt.setInt(1,0);
cstmt.executeUpdate();
tx.commit();
Transaction tx =session.beginTransaction();
Connection conn=session.connection();
String str="{call UserUpdate(?)}"
;
CallableStatement cstmt= conn.prepareCall(str);
cstmt.setInt(1,0);
cstmt.executeUpdate();
tx.commit();
用JDBC API的好处是这样的..
它不用把大批量的数据事先加载到内存中,然后再进行更新与修改..所以不会消耗大量内存....
(小程序中是看不出什么差别的..当数据的记录达到一定的数据量的时候自然会发现用Hibernate API 与JDBC API的差别)
在一个就是只能一条记录进行批量更新..不像Hibernate中更新每一条的..