Mybatis 的三種執行器


在企業開發中, 對數據庫的批量操作, 是一個非常常見的操作, Mybatis提供了批量執行器, 來支持批量操作.

1. Mybatis sql執行器

Mybatis 支持全局修改執行器, 參數名為: defaultExecutorType. 但是筆者並不推薦這種方式,筆者建議在獲取sqlSession對象時設置.

Mybatis 共有三種執行器:

  • SIMPLE: 默認的執行器, 對每條sql進行預編譯->設置參數->執行等操作
  • BATCH: 批量執行器, 對相同sql進行一次預編譯, 然后設置參數, 最后統一執行操作
  • REUSE: REUSE 執行器會重用預處理語句(prepared statements

1.1 局部設置

在獲取sqlSession時設置, 需要注意的時, 如果選擇的是批量執行器時, 需要手工提交事務.

// 獲取指定執行器的sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)

// 獲取批量執行器時, 需要手動提交事務
sqlSession.commit();

1.2 全局配置

可在全局配置文件中配置, 但是筆者不推薦這種方式, 了解即可.

<settings>
    <setting name="defaultExecutorType" value="BATCH" />
</settings>

2. 三種執行器測試

對於單挑sql執行, 不同的執行器沒有太大的差異, 所以筆者使用批量插入操作來測試不同執行器的不同行為方式.
需要特別注意的時, 當選擇批量執行器時, 縱使在獲取sqlSession時, 設置了自動提交事務, 也需要手動提交事務

2.1 映射文件

為保證測試條件盡可能一致, 筆者寫里一個清空表的方法, 在每個測試用例執行之前, 先清空表.

<mapper namespace="org.zongf.learn.mybatis3.l01.mapper.StudentMapper">

    <!-- 清空表中數據, 同時重置自增序列從0開始 -->
    <delete id="clear">
        truncate table t_student
    </delete>

    <!-- 新增 -->
    <insert id="save" useGeneratedKeys="true" keyProperty="id">
        insert into t_student  values (null , #{name}, #{age}, #{sex}, #{birth})
    </insert>

</mapper>

2.2 測試用例

public class TestStudentMapper {

    // 批量保存方法
    private void batchSave(StudentMapper mapper) {

        // 初始化10000個對象
        List<StudentPO> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            list.add(new StudentPO("zhangsan_" + i, "M",20 + i % 10,  LocalDate.now()));
        }

        // 批量執行
        long start = System.currentTimeMillis();
        for (StudentPO studentPO : list) {
            mapper.save(studentPO);
        }
        long end = System.currentTimeMillis();

        // 輸出執行耗時
        System.out.println("耗時:" + (end - start) + " ms!");
    }

    // 每次執行前,請空表
    @Before
    public void setUp(){
        StudentMapper studentMapper = SqlSessionUtil.getMapper(StudentMapper.class);
        studentMapper.clear();
    }

    // 默認執行器
    @Test
    public void test_SIMPLE(){
        // 獲取自動提交事務的Maper
        StudentMapper mapper = SqlSessionUtil.getMapperAutoTx(StudentMapper.class); // 執行批量保存
        batchSave(mapper);
    }

    // 重用預編譯執行器
    @Test
    public void test_REUSE(){
        // 獲取批量保存sqlSession
        SqlSession sqlSession = SqlSessionUtil.openSession(ExecutorType.REUSE, true);

        // 獲取Mapper 對象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        // 執行批量保存
        batchSave(mapper);

    }

    // 批量執行器
    @Test
    public void test_BATCH(){
        // 獲取批量保存sqlSession
        SqlSession sqlSession = SqlSessionUtil.openSession(ExecutorType.BATCH, true);

        // 獲取Mapper 對象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        // 執行批量保存
        batchSave(mapper);

        sqlSession.commit();
    }
}    

3. 批量測試日志分析

 從測試結果可以看出, 在做批量操作時, 使用批量執行器, 性能會有很大的提升.

3.1 SIMPLE 方式

 從執行日志可以看出, 每次插入操作, 都會執行編譯, 設置參數, 執行sql操作.

[2019-06-13 11:30:38:812][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==>  Preparing: insert into t_student values (null , ?, ?, ?, ?) 
[2019-06-13 11:30:38:819][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==> Parameters: zhangsan_0(String), 20(Integer), M(String), 2019-06-13(Date)
[2019-06-13 11:30:38:824][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- <==    Updates: 1

[2019-06-13 11:30:38:827][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==>  Preparing: insert into t_student values (null , ?, ?, ?, ?) 
[2019-06-13 11:30:38:828][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==> Parameters: zhangsan_1(String), 21(Integer), M(String), 2019-06-13(Date)
[2019-06-13 11:30:38:832][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- <==    Updates: 1

[2019-06-13 11:30:38:833][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==>  Preparing: insert into t_student values (null , ?, ?, ?, ?) 
[2019-06-13 11:30:38:839][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==> Parameters: zhangsan_2(String), 22(Integer), M(String), 2019-06-13(Date)
[2019-06-13 11:30:38:841][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- <==    Updates: 1
...
耗時:21575 ms!

3.2 REUSE 方式

從執行日志可以看出, 只有第一次插入操作, 執行了sql編譯步驟, 對其它插入操作執行了設置參數, 執行sql的操作.

[2019-06-13 11:31:11:752][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==>  Preparing: insert into t_student values (null , ?, ?, ?, ?) 

[2019-06-13 11:31:11:757][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==> Parameters: zhangsan_0(String), 20(Integer), M(String), 2019-06-13(Date)
[2019-06-13 11:31:11:759][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- <==    Updates: 1

[2019-06-13 11:31:11:761][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==> Parameters: zhangsan_1(String), 21(Integer), M(String), 2019-06-13(Date)
[2019-06-13 11:31:11:764][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- <==    Updates: 1

[2019-06-13 11:31:11:776][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==> Parameters: zhangsan_2(String), 22(Integer), M(String), 2019-06-13(Date)
[2019-06-13 11:31:11:778][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- <==    Updates: 1
...
耗時:19322 ms!

3.3 BATCH

從執行日志可以看出, 只對第一次插入操作執行了sql編譯操作, 對其它插入操作僅執行了設置參數操作, 最后統一執行.

[2019-06-13 11:31:29:270][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==>  Preparing: insert into t_student values (null , ?, ?, ?, ?) 
[2019-06-13 11:31:29:276][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==> Parameters: zhangsan_0(String), 20(Integer), M(String), 2019-06-13(Date)
[2019-06-13 11:31:29:277][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==> Parameters: zhangsan_1(String), 21(Integer), M(String), 2019-06-13(Date)
[2019-06-13 11:31:29:277][main][DEBUG][o.z.l.m.l.mapper.StudentMapper.save]- ==> Parameters: zhangsan_2(String), 22(Integer), M(String), 2019-06-13(Date)
...
耗時:835 ms!

 

 參考:https://blog.csdn.net/zongf0504/article/details/100104029


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM