1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        MyBatis三種批量插入方式的比較

        共 9678字,需瀏覽 20分鐘

         ·

        2021-09-28 09:53

        點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

        優(yōu)質(zhì)文章,第一時間送達(dá)

        數(shù)據(jù)庫使用的是sqlserver,JDK版本1.8,運(yùn)行在SpringBoot環(huán)境下
        對比3種可用的方式

        1. 反復(fù)執(zhí)行單條插入語句

        2. xml拼接sql

        3. 批處理執(zhí)行

        先說結(jié)論:少量插入請使用反復(fù)插入單條數(shù)據(jù),方便。數(shù)量較多請使用批處理方式。(可以考慮以有需求的插入數(shù)據(jù)量20條左右為界吧,在我的測試和數(shù)據(jù)庫環(huán)境下耗時都是百毫秒級的,方便最重要)。無論何時都不用xml拼接sql的方式。

        代碼

        拼接SQL的xml
        newId()是sqlserver生成UUID的函數(shù),與本文內(nèi)容無關(guān)

        <insert id="insertByBatch" parameterType="java.util.List">
            INSERT INTO tb_item VALUES
            <foreach collection="list" item="item" index="index" separator=",">
                (newId(),#{item.uniqueCode},#{item.projectId},#{item.name},#{item.type},#{item.packageUnique},
                #{item.isPackage},#{item.factoryId},#{item.projectName},#{item.spec},#{item.length},#{item.weight},
                #{item.material},#{item.setupPosition},#{item.areaPosition},#{item.bottomHeight},#{item.topHeight},
                #{item.serialNumber},#{item.createTime}</foreach>
        </insert>

        Mapper接口
        Mapper<Item> 是 mybatis插件tk.Mapper 的接口,與本文內(nèi)容關(guān)系不大

        public interface ItemMapper extends Mapper<Item> {
            int insertByBatch(List<Item> itemList);
        }

        Service類

        @Service
        public class ItemService {
            @Autowired
            private ItemMapper itemMapper;
            @Autowired
            private SqlSessionFactory sqlSessionFactory;
            //批處理
            @Transactional
            public void add(List<Item> itemList) {
                SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
                ItemMapper mapper = session.getMapper(ItemMapper.class);
                for (int i = 0; i < itemList.size(); i++) {
                    mapper.insertSelective(itemList.get(i));
                    if(i%1000==999){//每1000條提交一次防止內(nèi)存溢出
                        session.commit();
                        session.clearCache();
                    }
                }
                session.commit();
                session.clearCache();
            }
            //拼接sql
            @Transactional
            public void add1(List<Item> itemList) {
                itemList.insertByBatch(itemMapper::insertSelective);
            }
            //循環(huán)插入
            @Transactional
            public void add2(List<Item> itemList) {
                itemList.forEach(itemMapper::insertSelective);
            }
        }

        測試類

        @RunWith(SpringRunner.class)
        @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ApplicationBoot.class)
        public class ItemServiceTest {
            @Autowired
            ItemService itemService;

            private List<Item> itemList = new ArrayList<>();
            //生成測試List
            @Before 
            public void createList(){
                String json ="{\n" +
                        "        \"areaPosition\": \"TEST\",\n" +
                        "        \"bottomHeight\": 5,\n" +
                        "        \"factoryId\": \"0\",\n" +
                        "        \"length\": 233.233,\n" +
                        "        \"material\": \"Q345B\",\n" +
                        "        \"name\": \"TEST\",\n" +
                        "        \"package\": false,\n" +
                        "        \"packageUnique\": \"45f8a0ba0bf048839df85f32ebe5bb81\",\n" +
                        "        \"projectId\": \"094b5eb5e0384bb1aaa822880a428b6d\",\n" +
                        "        \"projectName\": \"項(xiàng)目_TEST1\",\n" +
                        "        \"serialNumber\": \"1/2\",\n" +
                        "        \"setupPosition\": \"1B柱\",\n" +
                        "        \"spec\": \"200X200X200\",\n" +
                        "        \"topHeight\": 10,\n" +
                        "        \"type\": \"Steel\",\n" +
                        "        \"uniqueCode\": \"12344312\",\n" +
                        "        \"weight\": 100\n" +
                        "    }";
                Item test1 = JSON.parseObject(json,Item.class);
                test1.setCreateTime(new Date());
                for (int i = 0; i < 1000; i++) {//測試會修改此數(shù)量
                    itemList.add(test1);
                }
            }
             //批處理
            @Test
            @Transactional
            public void tesInsert() {
                itemService.add(itemList);
            }
            //拼接字符串
            @Test
            @Transactional
            public void testInsert1(){
                itemService.add1(itemList);
            }
            //循環(huán)插入
            @Test
            @Transactional
            public void testInsert2(){
                itemService.add2(itemList);
            }
        }


        測試結(jié)果:

        10條 25條數(shù)據(jù)插入經(jīng)多次測試,波動性較大,但基本都在百毫秒級別

        方式50條100條500條1000條
        批處理159ms208ms305ms432ms
        xml拼接sql208ms232ms報(bào)錯報(bào)錯
        反復(fù)單條插入1013ms2266ms8141ms18861ms

        其中 拼接sql方式在插入500條和1000條時報(bào)錯(似乎是因?yàn)閟ql語句過長,此條跟數(shù)據(jù)庫類型有關(guān),未做其他數(shù)據(jù)庫的測試):
        com.microsoft.sqlserver.jdbc.SQLServerException: 傳入的表格格式數(shù)據(jù)流(TDS)遠(yuǎn)程過程調(diào)用(RPC)協(xié)議流不正確。此 RPC 請求中提供了過多的參數(shù)。最多應(yīng)為 2100

        可以發(fā)現(xiàn)

        • 循環(huán)插入的時間復(fù)雜度是 O(n),并且常數(shù)C很大

        • 拼接SQL插入的時間復(fù)雜度(應(yīng)該)是 O(logn),但是成功完成次數(shù)不多,不確定

        • 批處理的效率的時間復(fù)雜度是 O(logn),并且常數(shù)C也比較小

        結(jié)論

        循環(huán)插入單條數(shù)據(jù)雖然效率極低,但是代碼量極少,在使用tk.Mapper的插件情況下,僅需代碼,:

        @Transactional
        public void add1(List<Item> itemList) {
            itemList.forEach(itemMapper::insertSelective);
        }

        因此,在需求插入數(shù)據(jù)數(shù)量不多的情況下肯定用它了。

        xml拼接sql是最不推薦的方式,使用時有大段的xml和sql語句要寫,很容易出錯,工作效率很低。更關(guān)鍵點(diǎn)是,雖然效率尚可,但是真正需要效率的時候你掛了,要你何用?

        批處理執(zhí)行是有大數(shù)據(jù)量插入時推薦的做法,使用起來也比較方便。


           作者 |  樓主樓主

        來源 |   jianshu.com/p/cce617be9f9e


        加鋒哥微信: java3459  
        圍觀鋒哥朋友圈,每天推送Java干貨!

        瀏覽 28
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            91精品国产92久久久久 | 老师下面水好多 | 午夜精品久久久久 | 国语一级片| 97香蕉久久国产超碰青草国产区 | 精品永久中国 | 国产精品美女久久久久久久久 | 久久精国产 | 国产污视频网站 | 色偷偷网站 |