转自https://blog.csdn.net/an_2016/article/details/51759890
一、批量插入(两种方式)
1,通过Hibernate缓存
如果这样写代码进行批量插入(初始设想):
-
package com.anlw.util;
-
-
import org.hibernate.Session;
-
import org.hibernate.SessionFactory;
-
import org.hibernate.Transaction;
-
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
-
import org.hibernate.cfg.Configuration;
-
import org.hibernate.service.ServiceRegistry;
-
-
import com.anlw.entity.Student;
-
-
public
class SessionUtil {
-
Configuration conf =
null;
-
ServiceRegistry st =
null;
-
SessionFactory sf =
null;
-
Session sess =
null;
-
Transaction tx =
null;
-
-
public void HIbernateTest() {
-
conf =
new Configuration().configure();
-
st =
new StandardServiceRegistryBuilder().applySettings(conf.getProperties()).build();
-
sf = conf.buildSessionFactory(st);
-
try {
-
sess = sf.openSession();
-
tx = sess.beginTransaction();
-
for (
int i =
0; i <
10; i++) {
-
Student s =
new Student();
-
s.setAge(i +
1);
-
s.setName(
"test");
-
sess.save(s);
-
}
-
tx.commit();
-
}
catch (Exception e) {
-
if (tx !=
null) {
-
tx.rollback();
-
}
-
}
finally {
-
sess.close();
-
sf.close();
-
}
-
}
-
-
public static void main(String[] args) {
-
new SessionUtil().HIbernateTest();
-
}
-
}
如果数据量太大,会有可能出现内存溢出的异常;
小知识:
(1).Hibernate一级缓存,对其容量没有限制,强制使用,由于所有的对象都被保存到这个缓存中,内存总会达到一定数目时出现内存溢出的情况;
(2).Hibernate二级缓存可以进行大小配置;
要解决内存溢出的问题,就应该定时的将Sessiion缓存中的数据刷到数据库,正确的批量插入方式:
(1).设置批量尺寸(博主至今还没有明白下面这个属性和flush()方法的区别)
<property name="hibernate.jdbc.batch_size">2</property>
配置这个参数的原因就是尽量少读数据库,该参数值越大,读数据库的次数越少,速度越快;上面这个配置,是Hibernate是等到程序积累了100个sql之后在批量提交;
(2).关闭二级缓存(这个博主也不是很明白)
<property name="hibernate.cache.use_second_level_cache">false</property>
除了Session级别的一级缓存,Hibernate还有一个SessionFactory级别的二级缓存,如果启用了二级缓存,从机制上来说,Hibernate为了维护二级缓存,在批量插入时,hibernate会将对象纳入二级缓存,性能上就会有很大损失,也可能引发异常,因此最好关闭SessionFactory级别的二级缓存;
(3).在一二设置完成的基础上,清空Session级别的一级缓存;
-
package com.anlw.util;
-
-
import org.hibernate.Session;
-
import org.hibernate.SessionFactory;
-
import org.hibernate.Transaction;
-
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
-
import org.hibernate.cfg.Configuration;
-
import org.hibernate.service.ServiceRegistry;
-
-
import com.anlw.entity.Student;
-
-
public
class SessionUtil {
-
Configuration conf =
null;
-
ServiceRegistry st =
null;
-
SessionFactory sf =
null;
-
Session sess =
null;
-
Transaction tx =
null;
-
-
public void HIbernateTest() {
-
conf =
new Configuration().configure();
-
st =
new StandardServiceRegistryBuilder().applySettings(conf.getProperties()).build();
-
sf = conf.buildSessionFactory(st);
-
try {
-
sess = sf.openSession();
-
tx = sess.beginTransaction();
-
for (
int i =
0; i <
10; i++) {
-
Student s =
new Student();
-
s.setAge(i +
1);
-
s.setName(
"test");
-
sess.save(s);
-
if(i%
100 ==
0){
//以每100个数据作为一个处理单元
-
sess.flush();
//保持与数据库数据的同步
-
sess.clear();
//清楚Session级别的一级缓存的全部数据,及时释放占用的内存
-
}
-
}
-
tx.commit();
-
}
catch (Exception e) {
-
if (tx !=
null) {
-
tx.rollback();
-
}
-
}
finally {
-
sess.close();
-
sf.close();
-
}
-
}
-
-
public static void main(String[] args) {
-
new SessionUtil().HIbernateTest();
-
}
-
}
2,绕过Hibernate,直接调用JDBC API
-
package com.anlw.util;
-
-
import java.sql.Connection;
-
import java.sql.PreparedStatement;
-
import java.sql.SQLException;
-
-
import org.hibernate.Session;
-
import org.hibernate.SessionFactory;
-
import org.hibernate.Transaction;
-
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
-
import org.hibernate.cfg.Configuration;
-
import org.hibernate.jdbc.Work;
-
import org.hibernate.service.ServiceRegistry;
-
-
public
class SessionUtil {
-
Configuration conf =
null;
-
ServiceRegistry st =
null;
-
SessionFactory sf =
null;
-
Session sess =
null;
-
Transaction tx =
null;
-
-
public void HIbernateTest() {
-
conf =
new Configuration().configure();
-
st =
new StandardServiceRegistryBuilder().applySettings(conf.getProperties()).build();
-
sf = conf.buildSessionFactory(st);
-
try {
-
sess = sf.openSession();
-
tx = sess.beginTransaction();
-
//执行Work对象指定的操作,即调用Work对象的execute()方法
-
//Session会把当前使用的数据库连接传给execute()方法
-
sess.doWork(
new Work() {
-
-
@Override
-
public void execute(Connection arg0) throws SQLException {
//需要注意的是,不需要调用close()方法关闭这个连接
-
//通过JDBC API执行用于批量插入的sql语句
-
String sql =
"insert into student(name,age) values(?,?)";
-
PreparedStatement ps = arg0.prepareStatement(sql);
-
for(
int i=
0;i<
10;i++){
-
ps.setString(
1,
"kobe");
-
ps.setInt(
2,
12);
-
ps.addBatch();
-
}
-
ps.executeBatch();
-
}
-
});
-
tx.commit();
-
}
catch (Exception e) {
-
if (tx !=
null) {
-
tx.rollback();
-
}
-
}
finally {
-
sess.close();
-
sf.close();
-
}
-
}
-
-
public static void main(String[] args) {
-
new SessionUtil().HIbernateTest();
-
}
-
}
注意:通过JDBC API中的PreparedStatement接口来执行sql语句,sql语句涉及到的数据不会被加载到Session的缓存中,因此不会占用内存空间,因此直接调用JDBC API批量化插入的效率要高于Hibernate缓存的批量插入;
本人用的是第二种方法,速度比第一种很快