深入探讨 Spring Boot3 整合 MyBatis 实现批量添加数据

B站影视 内地电影 2025-09-18 00:06 1

摘要:在互联网软件开发领域,数据处理是日常开发工作中的关键环节。对于使用 Spring Boot3 框架进行后端开发,同时又借助 MyBatis 进行数据库操作的开发者来说,掌握高效的数据操作技巧至关重要。其中,批量添加数据是一种常见且对性能要求较高的操作场景,比如

在互联网软件开发领域,数据处理是日常开发工作中的关键环节。对于使用 Spring Boot3 框架进行后端开发,同时又借助 MyBatis 进行数据库操作的开发者来说,掌握高效的数据操作技巧至关重要。其中,批量添加数据是一种常见且对性能要求较高的操作场景,比如在进行数据初始化、数据迁移或者大数据量导入时,都需要考虑如何优化批量添加数据的过程,以提升系统整体性能和响应速度。本文将深入探讨在 Spring Boot3 中整合 MyBatis 实现批量添加数据的多种方式,并分析其优缺点以及性能优化策略。

(一)for 语句循环插入

原理:通过 for 循环,将数据一条一条地插入到数据库中。在每次循环中,创建一个新的数据库连接,执行插入操作,然后关闭连接。例如,假设有一个包含用户信息的列表,我们需要将这些用户信息插入到数据库的用户表中,代码实现可能如下:

for (User user : userList) {// 创建数据库连接Connection connection = DriverManager.getConnection(url, username, password);// 创建PreparedStatement对象PreparedStatement statement = connection.prepareStatement("INSERT INTO user (name, age, email) VALUES (?,?,?)");statement.setString(1, user.getName);statement.setInt(2, user.getAge);statement.setString(3, user.getEmail);// 执行插入操作statement.executeUpdate;// 关闭连接statement.close;connection.close;}

优势:JDBC 中的 PreparedStatement 有预编译功能,预编译之后会缓存起来,之后 SQL 执行会比较快,且 JDBC 可以开启批处理。如果网络环境良好且数据量较小,这种方式在代码实现上相对简单直观,易于理解和维护。

劣势:当插入大量数据时,这种方式的效率非常低下。因为每次插入都需要建立新的数据库连接,执行 SQL 语句,然后关闭连接,这一系列操作涉及到大量的网络 IO 开销。特别是当应用服务器和数据库服务器不在同一台机器上时,网络延迟可能会严重拖慢 SQL 执行的速度。而且频繁地创建和关闭连接也会增加系统资源的消耗,容易导致性能瓶颈。

(二)利用 MyBatis 的 foreach 来实现循环插入

原理:MyBatis 提供了强大的动态 SQL 功能,其中的标签可以用于将集合数据拼接成一条 SQL 语句进行插入。例如,我们有一个用户列表userList,希望将这些用户批量插入到数据库中,在 MyBatis 的 Mapper XML 文件中可以这样配置:

INSERT INTO user (name, age, email) VALUES(#{user.name}, #{user.age}, #{user.email})

在 Java 代码中,只需要调用对应的 Mapper 接口方法,并传入用户列表即可:

userMapper.batchInsertUsers(userList);

优势:这种方式最大的优点是不需要频繁访问数据库,所有数据通过一次 SQL 语句执行插入操作,大大减少了数据库连接的建立和关闭次数,提高了执行效率。相比 for 循环插入,减少了网络 IO 的开销,在一定程度上提升了性能。

劣势:当数据量非常大时,会出现拼接的 SQL 语句超长而执行失败的情况。因为 MySQL 等数据库对 SQL 语句的长度有一定限制,如果拼接的 SQL 语句超过了这个限制,数据库将无法执行该语句。此外,由于所有数据都在一条 SQL 语句中,无法充分发挥 PreparedStatement 预编译的优势,每次执行都需要重新解析 SQL 语句,且无法复用预编译结果。例如,当数据量达到几十万甚至上百万条时,拼接后的 SQL 语句可能会达到几 MB 甚至更大,这很容易导致数据库报错。

(三)使用 sqlSessionFactory 实现批量插入

原理:通过 SqlSessionFactory 获取 SqlSession,并设置为批处理模式(ExecutorType.BATCH),然后通过 Mapper 接口进行批量插入。在这种模式下,MyBatis 会将多个插入操作缓存起来,直到达到一定的批次数量或者手动调用提交方法时,才一次性将这些操作发送到数据库执行。示例代码如下:

// 获取批处理模式的SqlSessionSqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);try {UserMapper userMapper = sqlSession.getMapper(UserMapper.class);for (User user : userList) {userMapper.insert(user);}// 手动提交事务sqlSession.commit;} catch (Exception e) {sqlSession.rollback;throw e;} finally {sqlSession.close;}

优势:这种方式综合了前两种方式的优点。它既减少了数据库连接的频繁创建和关闭,降低了网络 IO 开销,又能够充分利用 PreparedStatement 的预编译功能,提高 SQL 执行效率。而且通过设置批处理模式,可以灵活控制每次提交到数据库的操作数量,避免因数据量过大导致的 SQL 语句超长问题。在处理大数据量时,性能表现非常出色,是一种比较推荐的批量插入方式。

劣势:相对于前两种方式,代码实现稍微复杂一些,需要手动管理 SqlSession 的生命周期,包括获取、使用、提交和关闭等操作。如果在代码中没有正确处理这些操作,可能会导致资源泄漏或者事务处理异常等问题。

(一)JDBC URL 配置优化

在 JDBC URL 中添加rewriteBatchedStatements=true参数,可以启用 MySQL 的真正批处理功能。默认情况下,MySQL 的 JDBC 驱动可能不会将多条 SQL 语句合并成一个批量操作发送到数据库,通过添加这个参数,可以强制驱动将多条 INSERT 语句合并为一条,从而大大提升性能。例如:

spring.datasource.url=jdbc:mysql://localhost:3306/yourdatabase?useSSL=false&rewriteBatchedStatements=true

根据实际测试,启用该参数后,批量插入数据的性能可以提升 5 - 10 倍。

(二)合理设置批次大小

在使用批处理模式时,合理设置每批处理的数据量非常重要。批次大小过小,会导致频繁地向数据库提交数据,增加网络 IO 和事务开销;批次大小过大,可能会导致内存占用过高,甚至出现 SQL 语句超长的问题。一般来说,每批处理 500 - 1000 条数据是一个比较合适的范围,可以根据实际业务场景和数据库性能进行调整。例如,在使用sqlSessionFactory实现批量插入时,可以在循环中进行如下控制:

int batchSize = 500;for (int i = 0; i

(三)事务控制

确保在 Service 层使用@Transactional注解,将批量插入操作放在一个事务中。这样可以保证数据的一致性,避免在部分数据插入成功而部分失败的情况下,数据处于不一致的状态。同时,大事务可以减少事务提交的次数,降低事务开销。例如:

@Servicepublic class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Override@Transactionalpublic void batchInsertUsers(List userList) {// 批量插入逻辑}}

(四)选择高性能连接池

Spring Boot 默认集成了 HikariCP 连接池,它具有高性能、低延迟等优点。在进行批量数据操作时,连接池的性能对整体性能也有很大影响。HikariCP 通过优化连接的创建、获取和释放等操作,能够快速响应应用程序对数据库连接的请求,减少等待时间。如果没有特殊需求,建议使用 Spring Boot 默认的 HikariCP 连接池,不需要额外引入其他连接池依赖。

代码实现示例

(一)项目依赖配置

在pom.xml文件中添加 Spring Boot、MyBatis 以及 MySQL 驱动等相关依赖:

org.springframework.bootspring-boot-starter-weborg.mybatis.spring.bootmybatis-spring-boot-starter2.2.0mysqlmysql-connector-java

(二)实体类定义

创建一个User实体类,用于映射数据库中的用户表:

public class User {private Long id;private String name;private Integer age;private String email;// 省略getter和setter方法}

(三)Mapper 接口定义

定义UserMapper接口,包含批量插入方法:

@Mapperpublic interface UserMapper {// 使用MyBatis的foreach标签实现批量插入int batchInsertByForeach(@Param("users") List users);// 使用sqlSessionFactory实现批量插入时调用的单条插入方法void insert(User user);}

(四)Mapper XML 文件配置

在UserMapper.xml文件中配置 SQL 语句:

INSERT INTO user (name, age, email) VALUES(#{user.name}, #{user.age}, #{user.email})INSERT INTO user (name, age, email) VALUES (#{name}, #{age}, #{email})

(五)Service 层实现

创建UserService接口及其实现类UserServiceImpl:

public interface UserService {void batchInsertUsers(List userList);}@Servicepublic class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate SqlSessionTemplate sqlSessionTemplate;@Override@Transactionalpublic void batchInsertUsers(List userList) {// 使用MyBatis的foreach标签实现批量插入if (userList != null &&!userList.isEmpty) {userMapper.batchInsertByForeach(userList);}// 使用sqlSessionFactory实现批量插入SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory.openSession(ExecutorType.BATCH, false);try {UserMapper mapper = sqlSession.getMapper(UserMapper.class);for (User user : userList) {mapper.insert(user);}sqlSession.commit;} catch (Exception e) {sqlSession.rollback;throw e;} finally {sqlSession.close;}}}

(六)Controller 层实现

创建UserController用于接收前端请求并调用 Service 层方法:

@RestController@RequestMapping("/users")public class UserController {@Autowiredprivate UserService userService;@PostMapping("/batchInsert")public String batchInsertUsers(@RequestBody List userList) {userService.batchInsertUsers(userList);return "批量插入成功";}}

在 Spring Boot3 中整合 MyBatis 实现批量添加数据,有多种方式可供选择,每种方式都有其优缺点和适用场景。开发者需要根据实际业务需求、数据量大小以及系统性能要求等因素,综合考虑选择合适的批量插入方式,并结合性能优化策略,提升系统的整体性能和稳定性。通过合理地配置 JDBC URL、设置批次大小、控制事务以及选择高性能连接池等措施,可以显著提高批量添加数据的效率,为用户提供更优质的服务体验。希望本文所介绍的内容能够对广大互联网软件开发人员在实际项目中有所帮助,让大家在处理批量数据操作时更加得心应手。

来源:从程序员到架构师一点号

相关推荐