不管三七二十一
/**
* Created by Administrator on 2019/1/12.
* 描述: 批量入库的持久化方法实现类
*
* @author Young
* @create 2019-01-12 20:06
*/
@Repository
public class BaseDaoImpl<T, ID extends Serializable> implements BaseDao<T, ID> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@PersistenceContext
private EntityManager entityManager;
@Transactional(readOnly = true)
@Override
public void save(List<T> entityList) {
int size = entityList.size();
logger.debug("获取到执行的数据是size:" + size);
for (int i = 0; i < size; i++) {
entityManager.persist(entityList.get(i));
if (i % 500 == 0 || i == (size - 1)) {
entityManager.flush();
entityManager.clear();
}
}
logger.debug("执行结束数据的size:" + size);
}
}
/**
* Created by Administrator on 2019/1/12.
* 描述: 持久层的接口方法
*
* @author Young
* @create 2019-01-12 20:05
*/
public interface BaseDao<T,ID extends Serializable> {
/**
* 保存数据对象
* @param entityList
* @return
*/
void save(List<T> entityList);
}
一开始使用的jpa的crud的save方法.每次save之前都要select一下,效率低下....
换peisist后,效率是生了...1s 4000左右,但是还是太少了...烦....
但看了大佬们用的批处理的方式,虽然不是使用jpa的,但是效率如果可以起来的话,未尝不可,所以还是先马了....然后再仔细分析
https://www.ablanxue.com/prone_13223_1.html 大佬的
java自带的批量操作,就可以很好的支持大量数据的处理。相比c#,简单很多。c#要使用oracle提供的ODP.NET,效率才很高,但是代码却很复杂。总之,在这方面,c#没得比。当然,这里的表是没加索引的,加了索引,效率会变慢,但是还是很高效。
long startTime=System.currentTimeMillis();
Connection conn=null;
try{
conn=getConnection();
conn.setAutoCommit(false);
PreparedStatement stmt=conn.prepareStatement("INSERT INTO product_tmp VALUES (?,?,?,?)");
System.out.println("数据大小:"+datas.size()); //1000000
int num=0;
for(Values v:datas){
num++;
stmt.setInt(1, v.getId());
stmt.setString(2, v.getStr1());
stmt.setString(3, v.getStr2());
stmt.setString(4, v.getStr3());
stmt.addBatch();
//注意: 每5万,提交一次;这里不能一次提交过多的数据,我测试了一下,6万5000是极限,6万6000就会出问题,插入的数据量不对。
if(num>50000){
stmt.executeBatch();
conn.commit();
num=0;
}
}
stmt.executeBatch();
conn.commit();
}catch(Exception e){
conn.rollback();
e.printStackTrace();
}finally{
closeConnection(conn);
long endTime=System.currentTimeMillis();
System.out.println("方法执行时间:"+(endTime-startTime)+"ms");
}
另外一个大佬的,是做个总结
https://blog.youkuaiyun.com/liuxigiant/article/details/16939505 大佬,墙裂推荐
使用jdbc向数据库插入100000条记录,分别使用statement,PreparedStatement,及PreparedStatement+批处理3种方式进行测试:
public void exec(Connection conn){
try {
//开始时间
Long beginTime = System.currentTimeMillis();
//设置手动提交
conn.setAutoCommit(false);
Statement st = conn.createStatement();
for(int i=0;i<100000;i++){
String sql="insert into t1(id) values ("+i+")";
st.executeUpdate(sql);
}
//结束时间
Long endTime = System.currentTimeMillis();
System.out.println("st:"+(endTime-beginTime)/1000+"秒");//计算时间
st.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//2.使用PreparedStatement对象
public void exec2(Connection conn){
try {
Long beginTime = System.currentTimeMillis();
conn.setAutoCommit(false);//手动提交
PreparedStatement pst = conn.prepareStatement("insert into t1(id) values (?)");
for(int i=0;i<100000;i++){
pst.setInt(1, i);
pst.execute();
}
conn.commit();
Long endTime = System.currentTimeMillis();
System.out.println("pst:"+(endTime-beginTime)/1000+"秒");//计算时间
pst.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//3.使用PreparedStatement + 批处理
public void exec3(Connection conn){
try {
conn.setAutoCommit(false);
Long beginTime = System.currentTimeMillis();
//构造预处理statement
PreparedStatement pst = conn.prepareStatement("insert into t1(id) values (?)");
//1万次循环
for(int i=1;i<=100000;i++){
pst.setInt(1, i);
pst.addBatch();
//每1000次提交一次
if(i%1000==0){//可以设置不同的大小;如50,100,500,1000等等
pst.executeBatch();
conn.commit();
pst.clearBatch();
}
}
Long endTime = System.currentTimeMillis();
System.out.println("pst+batch:"+(endTime-beginTime)/1000+"秒");
pst.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
在Oracle 10g中测试,结果:
1.使用statement 耗时142秒;
2.使用PreparedStatement 耗时56秒;
3.使用PreparedStatement + 批处理耗时:
a.50条插入一次,耗时5秒;
b.100条插入一次,耗时2秒;
c.1000条以上插入一次,耗时1秒;
通过以上可以得出结论,在使用jdbc大批量插入数据时,明显使用第三种方式(PreparedStatement + 批处理)性能更优。
普通方式处理大量数据的insert时,处理速度相当慢。
*/
PreparedStatement ps = null;
//循环10000次
for(int i = 0; i < 100000; i++) {
ps = con.prepareStatement(sql);
ps.executeUpdate();
}
/**方法二:通过addBatch()的方式,将数据缓存在对象里面,通过最后执行executeBatch();方法提交,因此*速度会快很多!
*/
PreparedStatement ps = con.prepareStatement(sql);
for(int i = 0; i < 100000; i++) {
ps.setString(1, "1");
ps.setString(2, "2");
ps.addBatch();
}
ps.executeBatch();