通常在一个Session对象中存放的持久化对象是有限的。等到Session处理事物完毕,还要关闭Session对象,从而及时释放Session的缓存占用的内存。
当一个事物中要处理大批量的数据时,一般来说是应该尽量避免在应用层进行批量的操作,而应该在数据库层直接进行批量的操作。例如:直接在数据库中执行批量更新或删除的SQL语句,如果批量操作的逻辑比较复杂,则可以通过直接在数据库中运行存储过程来完成批量操作, 当然,在应用层也可以进行批量操作,主要有以下方式:
1)。通过Session来进行批量操作。
2)。通过StatelessSession来进行批量操作。
3)。通过HQL来进行批量操作。
4)。直接通过JDBC API来进行批量操作。
通过Session来进行批量操作:
Session的save()及update()方法都会把处理的对象存放在自己的缓存中,处理通过一个Session对象来处理大量持久化对象,应该及时的从缓存中清空已经处理完毕并且不在访问的对象,具体的做法是在处理完一个对象或者小批量后,立刻调用flush()方法清理缓存,然后调用clear()方法清空缓存。
通过Session来进行批量处理会受到以下约束:
1)。需要在hibernate的配置文件中设置jdbc单次批量处理的数目,合理的取值通常为10~50
hibernate.jdbc.batch_size
2)。如果对象采用“identity”标示符生成器,则无法在jdbc层进行批量操作。
3)。进行操作是建议关闭hibernate的第二级缓存。
批量插入:
Session session = Sessionfactory.openSession();
Transaction tx = session.beginTransaction();
for(int = 0; i <100000;i++){
Customer customer = new Customer(....);
session.save(customer);
if( i % 20 == 0){//单次批量操作数量为20
session.flush();//清理缓存,执行批量插入20条记录的SQL insert语句
session.clear();//清空缓存中的Customer对象
}
}
tx.commit();
session.close();
批量更新:
Session session = new Sessionfactory.openSession();
Transaction tx = session.beginTransction();
ScrollableReaults customers = session.createQuery("from Customer");
int count = 0;
while(customer.next()){
Custmoer customer = new Custmoer(............);
customer.setAge(customer.getAge()+1);//更新Custmoer对象age的属性
if(++count % 20 == 0){
session.flush();//清理缓存
session.clear();//清空缓存中的Customer对象
}
}
tx.commit();
session.close();
通过StatelessSession来进行批量操作
Session 具有一个用于保存内存中对象与数据库中相应数据保持同步的缓存,位于缓存中的对象为持久化对象,但在进行批量操作的时候,把大量对象放入缓存中会消耗大量的内存空间,作为一种
替代方案,可以采用无状态的StatelessSession来进行批量的操作。
StatelessSession session = sessionFactory.openStatelessSession();
Transaction tx = session.beginTransaction();
ScrollableResults customers = session.getNamedQuery("GetCustomers")
.scroll(ScrollMode.FORWQRD_ONLY);
while(customers.next()){
Customer customer = (Customer) customer.get(0);
customer.setAge(customer.getAge()+1);//在内存中更新Customer对象的age属性
session.update(customer);//立即执行update语句,更新数据库中相应数据
}
tx.commit();
session.close();
从形式上看StatelessSession与Session的用法有点相似,有以下区别:
1)。StatelessSession没有缓存,通过StatelessSession来加载,保存或更新后的对象都处于游离状态。
2)。StatelessSession不会雨hibernate的第二级缓存交互。
3)。当调用StatelessSession的save()、update()或delete()方法时,这些方法会立即执行相应的SQL语句,而不会仅计划执行一条SQL语句。
4)。StatelessSession不会对所加载的对象自动进行脏检查,所以在以上程序中修改了内存中的Customer对象的属性后,还需要通过StatelessSession的update()更新数据库中的相应数据。
5)。StatelessSession不会对关联的对象进行任何级联操作。
6)。StatelessSession所做的操作可以被Interceptor拦截器捕获到,但会被hibernate的时间处理所忽略!
7)。通过一个StatelessSession对象两次加载OID为1的Customer对象时,会得到两个不同内存地址的Customer。
通过HQL来进行批量操作:
Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
int updateEntieies = session.createQuery(hqlUpdate);
.setString("newName","Mike")
.setString("oldName","Tom")
.executeUpdate();
tx.commit();
session.close();
通过JDBC API来进行批量操作:
Transaction tx = session.beginTransaction();
java.sql.Connection con = session.connection();
PreparedStatement stmt = con.prepareStatement("update CUSTOMER set AGE = AGE + 1 where = AGE > 0");
stmt.executeUpdate();
tx.commit();
*在hibernate3中尽管Session的connection()方法还存在,但是已经被废弃,不提倡使用了,不过Hibernate3提供了替代的方案:org.hibernate.jdbc.Work接口表示直接通过JDBC API来
访问数据库的操作,Work接口的execute()方法用于执行直接通过JDBC API来访问数据库的操作。
public interface Work{
//直接通过JDBC API 来访问数据库
public void execute(Connection connection ) throws SQLExectpion;
}
Transaction tx = session.beginTransaction();
Work work = new Work(){
public void execute(Connection connection ) throws SQLException{
PreparedStatement stmt = connection.prepareStatement("update CUSTOMER set AGE = AGE + 1 where AGE > 0");
stmt.executeUpdate();
}
}
//执行Work
session.doWork(work);
tx.commit();