Hibernate批量操作笔记

本文介绍了在处理大量数据插入、更新和删除时,使用Hibernate缓存和直接调用JDBC API的批量操作方法。针对内存溢出问题,提出了设置Hibernate批量尺寸、关闭二级缓存以及适时清空一级缓存的解决方案。同时,对比了Hibernate与JDBC在批量操作上的性能和内存占用,指出JDBC在某些场景下更具优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、批量插入

大量记录插入数据库有两种处理方式:通过Hibernate缓存、绕过Hibernate直接调用JDBC API。

(1)hibernate缓存

private void testBatchAddByCache(){

Session session=null;

Transaction tx=null;

try{

session=HibernateSessionFactory.getSession();

tx=session.beginTransaction();

for(int i=0;i<1000000;i++){

Users user=new Users();

user.setLoginName("u"+i);

session.save(user);

}

tx.commit();

```

}

}

运行测试,程序会在某个时候运行失败,并抛出OutofMemoryError

Hibernate缓存分为一级缓存和二级缓存,hibernate对两种缓存有不同的管理机制,对于二级缓存,可以对它大小进行相关设置,对于一级缓存,hibernate对它的容量没有限制。由于Hibernate的Session持有一个必选的一级缓存,执行海量数据插入时,所有的Users对象都被纳入一级缓存,这样内存就会一点一点被占用,直到内存溢出。

要解决问题,需要定时将Session缓存的数据刷入数据库,而不是一直在Session级别缓存

步骤:设置批量尺寸:在Hibernate配置文件hibernate.cfg.xml中设置hibernate.jdbc.batch_size属性<property name="hibernate.jdbc.batch_size">100</property>

关闭二级缓存,如果启用,hibernate为了维护二级缓存,批量插入时,hibernate会将Users对象纳入二级缓存,性能上会有很大损失,也可能发生异常。

在hibernate.cfg.xml中<property name="hibernate.cache.use_second_level_cache">false</property>

清空Session级别的一级缓存

testBatchAddByCache()方法中,添加:if(i%100==0){session.flush(); session.clear();}

(2)绕过hibernate直接调用JDBC API

private void testBatchAddByJDBC(){

Session session=null;

Transaction tx=null;

try```

session=HibernateSessionFactory.getSession();

tx=session.beginTransaction();

//执行Work对象指定的操作,即调用Work对象的execute()方法,Session会把当前使用的数据库连接传给execute()方法

session.doWork(

//定义一个匿名类,实现了Work接口

new Work(){

@Override

public void execute(Connection connection) throws SQLException{

//通过JDBC API执行用于批量插入的SQL语句

PreparedStatement ps=connection.prepareStatement("insert into users(LoginName,LoginPwd) values(?,?)");

for(int i=0;i<1000000;i++){

ps.setString(1,"u"+i);

ps.setString(2,"123456");

ps.addBatch();//将参数添加到PerparedStatement对象的批处理命令中

}

ps.executeBatch();//执行批处理

}

}

);

tx.commit();

```

}

从Hibernate4.0开始,去除了Session.connection()方法,用Session.doWork(Work work)方法替代,该方法用于执行Work对象指定的操作,,即调用execute()方法。

Session会把当前使用数据库连接传给execute()方法,需要注意,不要调用close()方法关闭这个连接。

控制台只显示一条insert语句用于插入批量数据(我测试的时候没显示···),当通过JDBC API中的PreparedStatement接口来执行SQL语句时,SQL语句中涉及到的数据不会被加载到Session缓存中,因此不会占用内存空间,另外,直接调用JDBC API批量插入的效率要高于通过Hibernate缓存的批量插入。


2、批量更新

(1)使用Hibernate直接进行批量更新:

由于Hibernate4.0及以上版本使用ASTQueryTranslatorFactory作为HQL/SQL查询翻译器,因此Hibernate的HQL直接支持update/delete的批量更新语法

private void testBatchUpdateByHql(){
Session session=null;
Transaction tx=null;
try{
session=HibernateSessionFactory.getSession();
tx=session.beginTransaction();
Query query=session.createQuery("update Users set loginPwd='111111'");
query.executeUpdate();
tx.commit();
}catch(Exception e){
e.printStackTrace();
tx.rollback();
}finally{
session.close();
}
}



(2)绕过Hibernate,调用JDBC API:

private void testBatchUpdateByJDBC(){
Session session=null;
Transaction tx=null;
try{
session=HibernateSessionFactory.getSession();
tx=session.beginTransaction();
session.doWork(new Work(){
@Override
public void execute(Connection connection) throws SQLException{
Statement st=connection.createStatement();
st.executeUpdate("update Users set LoginPwd='222222'");
}

}
);
tx.commit();
}catch(Exception e){
e.printStackTrace();
tx.rollback();
}finally{
session.close();
}
}


3、批量删除:

(1)使用Hibernate直接进行批量删除

private void testBatchDeleteByHql(){
Session session =null;
Transaction tx=null;
try{
session=HibernateSessionFactory.getSession();
tx=session.beginTransaction();
Query query=session.createQuery("delete Users where id>20");
query.executeUpdate();
tx.commit();
}catch(Exception e){
e.printStackTrace();
tx.rollback();
}finally{
session.close();
}
}


(2)绕过Hibernate,调用JDBC API

private void testBatchDeleteByJDBC(){
Session session=null;
Transaction tx=null;
try{
session=HibernateSessionFactory.getSession();
tx=session.beginTransaction();
session.doWork(new Work(){
@Override
public void execute(Connection connection) throws SQLException{
Statement st=connection.createStatement();
st.executeUpdate("delete from Users where id>=15");
}
});
tx.commit();
}catch(Exception e){
e.printStackTrace();
tx.rollback();
}finally{
session.close();
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值