您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關MyBatis如何批量插入大量數據,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
問題背景:只用MyBatis中foreach進行批量插入數據,一次性插入超過一千條的時候MyBatis開始報錯。項目使用技術:SpringBoot、MyBatis
批量插入碰到的問題:
java.lang.StackOverflowError: null
該問題是由于一次性插入數據1w條引起的,具體插入代碼如下:
userDao.batchInsert(list); <insert id="batchInsert" parameterType="java.util.List"> INSERT INTO USER <trim prefix="(" suffix=")" suffixOverrides=","> ID, AGE, NAME, EMAIL </trim> SELECT A.* FROM (<foreach collection="list" index="index" item="item" separator="UNION ALL"> SELECT sys_guid(), #{user.age}, #{user.name}, #{user.email} FROM dual </foreach>) A </insert>
以上的插入代碼其實也是一種批量插入的方式,但是他的靈界點并不高,插入數據過多的時候,可能需要我們使用代碼在一次分批。當然如果插入數據不超過5000的時候可以直接這么使用
插入1w條數據,發現出現錯誤,原因是數據量過大,棧內存溢出了。mybatis中直接使用foreach插入數據,就相當于將所有的sql預先拼接到一起,然后一起提交。這本身就是一種批量插入的處理方案,但是達不到我們要求。主要是插入有上限。如果需要更多的數據導入,我們需要更換一種方式來解決這個問題,mybatis中ExecutorType的使用。
Mybatis內置的ExecutorType有3種,SIMPLE、REUSE、BATCH; 默認的是simple,該模式下它為每個語句的執行創建一個新的預處理語句,單條提交sql;而batch模式重復使用已經預處理的語句,并且批量執行所有更新語句,顯然batch性能將更優;但batch模式也有自己的問題,比如在Insert操作時,在事務沒有提交之前,是沒有辦法獲取到自增的id,這在某型情形下是不符合業務要求的;
為了能夠高效,并且解決上述問題,我們使用ExecutorType,并分批插入。代碼如下:
//我們使用的是springboot,sqlSessionTemplate是可以自己注入的 @Autowired private SqlSessionTemplate sqlSessionTemplate; public void insertExcelData(List<User> list) { //如果自動提交設置為true,將無法控制提交的條數,改為最后統一提交,可能導致內存溢出 SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false); //不自動提交 try { UserDao userDao = session.getMapper(UserDao.class); for (int i = 0; i < list.size(); i++) { userDao.insert(list.get(i)); if (i % 400 == 0 || i == list.size() - 1) { //手動每400條提交一次,提交后無法回滾 session.commit(); //清理緩存,防止溢出 session.clearCache(); } } } catch (Exception e) { //沒有提交的數據可以回滾 session.rollback(); } finally { session.close(); } } userDao.insert(User user); <insert id="insert" parameterType="com.echo.UserPo"> insert into USER (id <if test="age != null"> ,age </if> <if test="name != null"> ,name </if> <if test="email != null"> ,email </if> ) values ( sys_guid() <if test="age != null"> ,#{age} </if> <if test="name != null"> ,#{name} </if> <if test="email != null"> ,#{email} </if>) </insert>
這里采用的是單條插入,直接使用for循環,但是使用ExecutorType.BACTH就相當于手動提交。這也是我們需要的效果,所以我們在循環里面判斷了,是否到了第400筆,如果到了第400筆就直接提交,然后清空緩存,防止溢出。這樣就有效的實現了批量插入,同時保證溢出問題的不出現
關于“MyBatis如何批量插入大量數據”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。