java
主页 > 软件编程 > java >

MyBatis执行批处理操作的实现

2024-07-09 | 佚名 | 点击:

在MyBatis中,批处理操作是一种高效执行多条语句的方式,特别是当你需要在一个事务中插入、更新或删除多条记录时。批处理可以显著减少与数据库的交互次数,从而提高性能。

执行批处理的基本步骤

示例代码

1

2

3

4

5

6

7

8

9

try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {

    YourMapper mapper = sqlSession.getMapper(YourMapper.class);

    for (YourData data : dataList) {

        // 根据需要调用insert, update或delete方法

        mapper.insertOrUpdate(data);

    }

    sqlSession.commit();

    // 可以获取批处理结果,处理特定逻辑

}

深入源码解析

在MyBatis中,批处理的核心是BatchExecutor,这是Executor的一个实现。在开启批处理模式时,MyBatis会使用BatchExecutor来处理SQL会话。

BatchExecutor的关键方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

@Override

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {

    final Configuration configuration = ms.getConfiguration();

    final StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);

    final BoundSql boundSql = handler.getBoundSql();

    final String sql = boundSql.getSql();

    final Statement stmt;

    if (sql.equals(currentSql) && ms.equals(currentStatement)) {

        int last = statementList.size() - 1;

        stmt = statementList.get(last);

        applyTransactionTimeout(stmt);

        handler.parameterize(stmt);//fix Issues 322

    } else {

        Connection connection = getConnection(ms.getStatementLog());

        stmt = handler.prepare(connection, transaction.getTimeout());

        handler.parameterize(stmt);    //fix Issues 322

        currentSql = sql;

        currentStatement = ms;

        statementList.add(stmt);

        batchResultList.add(new BatchResult(ms, sql, parameter));

    }

    handler.batch(stmt);

    return BATCH_UPDATE_RETURN_VALUE;

}

执行批处理

当调用commit或flushStatements时,BatchExecutor.doFlushStatements会被触发,它负责实际执行批处理操作。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

@Override

public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {

    try {

        if (isRollback) {

            return Collections.emptyList();

        }

 

        List<BatchResult> results = new ArrayList<>();

        if (statementList.size() > 0) {

            for (int i = 0, n = statementList.size(); i < n; i++) {

                Statement stmt = statementList.get(i);

                BatchResult batchResult = batchResultList.get(i);

                try {

                    batchResult.setUpdateCounts(stmt.executeBatch());

                    MappedStatement ms = batchResult.getMappedStatement();

                    List<Object> parameterObjects = batchResult.getParameterObjects();

                    KeyGenerator keyGenerator = ms.getKeyGenerator();

                    if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {

                        Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;

                        jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);

                    } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141

                        for (Object parameter : parameterObjects) {

                            keyGenerator.processAfter(this, ms, stmt, parameter);

                        }

                    }

                } finally {

                    closeStatement(stmt);

                }

            }

        }

        return results;

    } finally {

        for (Statement stmt : statementList) {

            closeStatement(stmt);

        }

        currentSql = null;

        statementList.clear();

        batchResultList.clear();

    }

}

小结

MyBatis的批处理通过BatchExecutor实现,它通过将SQL语句收集到批处理队列中,然后在适当的时候(如调用commit)一次性执行,以提高性能。正确使用批处理可以在执行大量类似操作时大幅度减少应用与数据库的交互次数,优化应用性能。不过,要注意批处理可能会对事务管理、错误处理等方面带来额外的复杂性,使用时需要特别留意。

原文链接:
相关文章
最新更新