java批量插入數(shù)據(jù)的幾種方法
批量插入數(shù)據(jù),常見的使用mybatis foreach 插入的方式,原始的方式和批處理
1,常見的mybatis foreach xml
<insert id="insertBatch" parameterType="java.util.List"> insert into CODEINFO (CODE_TYPE, CODE, MEAN, STATE, SORT_ID) values <foreach collection ="records" item="item" separator =","> (#{item.codeType}, #{item.code}, #{item.remark}, #{item.state}, #{item.sortId}) </foreach > </insert>
mapper:
int insertBatch(@Param("records") List<CodeInfo> records);
對(duì)于數(shù)據(jù)量不是很大的,基本夠用。如果同步數(shù)據(jù)特別慢,再考慮其它的方式?;蛘咄砩狭璩吭偻綌?shù)據(jù)。
2,原始的方式
批量插入
public void insertBatach(){ Connection conn=null; PreparedStatement ps=null; try { long start = System.currentTimeMillis(); conn = JDBCUtils.getConnection(); conn.setAutoCommit(false); String sql="INSERT INTO CODEINFO (CODE_TYPE, CODE, MEAN,STATE, SORT_ID) VALUES (?, ?, ?, ?, ?)"; ps = conn.prepareStatement(sql); for(int i=1;i<=20000;i++){ ps.setObject(1, "TEST_INSERT_BATCH"); ps.setObject(2, "0"+i); ps.setObject(3, "name_"+i); ps.setObject(4, "0SA"); ps.setObject(5, i); //1.sql ps.addBatch(); if(i%500==0){ //2.執(zhí)行batch ps.executeBatch(); //3.清空batch ps.clearBatch(); } } //提交數(shù)據(jù) conn.commit(); long end = System.currentTimeMillis(); System.out.println("批量插入花費(fèi)的時(shí)間為:"+(end-start)); } catch (Exception e) { e.printStackTrace(); } finally{ JDBCUtils.close(conn, ps); } }
數(shù)據(jù)庫連接:
import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class JDBCUtils { private static String url; private static String user; private static String password; private static Connection conn = null; // 靜態(tài)代碼塊 static{ /* 將外部properties文件放在src文件夾中,用類的加載器讀文件,格式: * 當(dāng)前類名.class.getClassLoader().getResourceAsStream("外部文件名");*/ InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("sql.properties"); Properties p=new Properties(); try { p.load(in); } catch (IOException e) { e.printStackTrace(); } // 讀文件給變量賦值 String driver = p.getProperty("driver"); url = p.getProperty("url"); user = p.getProperty("user"); password = p.getProperty("password"); try { Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } // 構(gòu)造獲得數(shù)據(jù)庫鏈接方法 public static Connection getConnection() { try { conn = DriverManager.getConnection(url, user, password); } catch (SQLException e) { e.printStackTrace(); } return conn; } // 構(gòu)造關(guān)閉流的方法 public static void close(Connection conn,Statement stat) { if (stat != null) { try { stat.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } // 重載關(guān)閉流的方法 public static void close(Connection conn,Statement stat, ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (stat != null) { try { stat.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
原始的方法寫起來麻煩些。
3,批處理
MybatisGeneralBatchUtils
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.transaction.support.TransactionSynchronizationManager; import java.util.List; import java.util.function.BiFunction; @Component public class MybatisGeneralBatchUtils { private static final Logger logger = LoggerFactory.getLogger(MybatisGeneralBatchUtils.class); /** * 每次處理1000條 */ private static final int BATCH_SIZE = 1000; /** * 批量處理修改或者插入 * 變成一條一條的數(shù)據(jù),然后最后一起執(zhí)行。并不是 insertBatch那種方式 * @param data 需要被處理的數(shù)據(jù) * @param mapperClass Mybatis的Mapper類 * @param function 自定義處理邏輯 * @return int 影響的總行數(shù) */ public <T, U, R> int batchUpdateOrInsert(List<T> data, Class<U> mapperClass, BiFunction<T, U, R> function) { int i = 1; SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) SpringUtil.getBean("sqlSessionFactory"); SqlSession batchSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); try { U mapper = batchSqlSession.getMapper(mapperClass); int size = data.size(); for (T element : data) { function.apply(element, mapper); if ((i % BATCH_SIZE == 0) || i == size) { batchSqlSession.flushStatements(); } i++; } // 非事務(wù)環(huán)境下強(qiáng)制commit,事務(wù)情況下該commit相當(dāng)于無效 batchSqlSession.commit(!TransactionSynchronizationManager.isSynchronizationActive()); } catch (Exception e) { batchSqlSession.rollback(); logger.error("batchUpdateOrInsert", e); } finally { batchSqlSession.close(); } return i - 1; } }
SpringUtil
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringUtil.applicationContext = applicationContext; } public static Object getBean(String name) { return applicationContext.getBean(name); } public static <T> T getBean(Class<T> clazz) { return applicationContext.getBean(clazz); } }
調(diào)用:
mapper:
int insertSelective(CodeInfo codeInfo);
xml:
<insert id="insertSelective" parameterType="com.web.dict.entity.CodeInfo"> insert into CODEINFO <trim prefix="(" suffix=")" suffixOverrides=","> <if test="codeType != null"> CODE_TYPE, </if> <if test="code != null"> CODE, </if> <if test="mean != null"> MEAN, </if> <if test="state != null"> STATE, </if> <if test="sortId != null"> SORT_ID, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="codeType != null"> #{codeType,jdbcType=VARCHAR}, </if> <if test="code != null"> #{code,jdbcType=VARCHAR}, </if> <if test="mean != null"> #{mean,jdbcType=VARCHAR}, </if> <if test="state != null"> #{state,jdbcType=VARCHAR}, </if> <if test="sortId != null"> #{sortId,jdbcType=VARCHAR}, </if> </trim> </insert>
service:
@Resource private MybatisGeneralBatchUtils mybatisGeneralBatchUtils; public int batchInsertData(List<CodeInfo> codeInfos){ return mybatisGeneralBatchUtils.batchUpdateOrInsert(codeInfos, CodeInfoMapper.class, (item, codeInfoMapper) -> codeInfoMapper.insertSelective(item)); }
這個(gè)方法看起來比較通用,但是我自己測(cè)的話,速度反而比較慢??赡苁且?yàn)槟M的字段和數(shù)據(jù)都比較少;后面有遇到數(shù)據(jù)量大的,再進(jìn)行一個(gè)比對(duì)。
官網(wǎng)推薦的方法:
MyBatis文檔中寫批量插入的時(shí)候,是推薦使用另外一種方法 中 Batch Insert Support 標(biāo)題里的內(nèi)容
try(SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class); List<SimpleTableRecord> records = getRecordsToInsert(); // not shown BatchInsert<SimpleTableRecord> batchInsert = insert(records) .into(simpleTable) .map(id).toProperty("id") .map(firstName).toProperty("firstName") .map(lastName).toProperty("lastName") .map(birthDate).toProperty("birthDate") .map(employed).toProperty("employed") .map(occupation).toProperty("occupation") .build() .render(RenderingStrategies.MYBATIS3); batchInsert.insertStatements().forEach(mapper::insert); session.commit(); }
總結(jié):
如果數(shù)據(jù)量不大,能第一種就夠了。如果數(shù)據(jù)內(nèi)容多,字段又多,試試其它的方式,看下效率是否有更快。 同步數(shù)據(jù),還是適合晚上的時(shí)候,用定時(shí)器去跑。
到此這篇關(guān)于java批量插入數(shù)據(jù)的幾種方法的文章就介紹到這了,更多相關(guān)java批量插入數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用@TransactionalEventListener監(jiān)聽事務(wù)教程
這篇文章主要介紹了使用@TransactionalEventListener監(jiān)聽事務(wù)教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09idea創(chuàng)建JAVA Class時(shí)自動(dòng)生成頭部文檔注釋的方法
這篇文章主要介紹了idea創(chuàng)建JAVA Class時(shí)自動(dòng)生成頭部文檔注釋的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12java中實(shí)現(xiàn)控制臺(tái)打印sql語句方式
這篇文章主要介紹了java中實(shí)現(xiàn)控制臺(tái)打印sql語句方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06Spring+Quartz實(shí)現(xiàn)動(dòng)態(tài)任務(wù)調(diào)度詳解
這篇文章主要介紹了Spring+Quartz實(shí)現(xiàn)動(dòng)態(tài)任務(wù)調(diào)度詳解,最近經(jīng)?;趕pring?boot寫定時(shí)任務(wù),并且是使用注解的方式進(jìn)行實(shí)現(xiàn),分成的方便將自己的類注入spring容器,需要的朋友可以參考下2024-01-01Java實(shí)現(xiàn)輸出回環(huán)數(shù)(螺旋矩陣)的方法示例
這篇文章主要介紹了Java實(shí)現(xiàn)輸出回環(huán)數(shù)(螺旋矩陣)的方法,涉及java針對(duì)數(shù)組的遍歷、判斷、輸出等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12一文詳解如何通過Java實(shí)現(xiàn)SSL交互功能
這篇文章主要為大家詳細(xì)介紹了如何通過Java實(shí)現(xiàn)SSL交互功能,文中的示例代碼講解詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的幫助,需要的可以參考一下2023-04-04