主页 > 软件开发  > 

高并发场景下的数据库优化

高并发场景下的数据库优化

在高并发系统中,数据库通常是性能瓶颈。面对高并发请求,我们需要采用合适的优化策略,以保证数据库的稳定性和高效性。本文将介绍数据库高并发问题的成因,并结合 Mybatis-Plus,探讨 乐观锁、悲观锁、高并发优化及数据库连接池优化 的最佳实践。


1. 数据库高并发问题分析 1.1 高并发数据库问题的常见表现 数据库连接耗尽:过多的并发请求导致数据库连接池资源被占满,新的请求无法获取连接。锁竞争严重:多个事务对同一行或同一表的数据竞争锁,导致等待时间变长,甚至发生死锁。读写压力过大:业务场景下 大量写操作(INSERT、UPDATE) 或 查询操作(SELECT) 导致数据库压力增大,影响系统响应时间。数据不一致:并发修改同一数据时,可能导致数据丢失或覆盖,产生 脏读、幻读、不可重复读 等问题。
2. 乐观锁与悲观锁的使用

在高并发场景下,数据库并发控制策略主要分为 乐观锁 和 悲观锁。 在高并发场景下,数据库并发控制策略主要分为 乐观锁 和 悲观锁。

2.1 乐观锁

适用场景:适用于 读多写少 的场景,例如 订单支付状态修改、库存扣减 等。

实现方式:

通过 版本号机制(Version) 进行更新。在 UPDATE 时,带上 version 条件,只有 version 匹配时才更新成功,否则更新失败。

Mybatis-Plus 乐观锁实现

在实体类中增加 @Version 注解 @Data @TableName("user") public class User { @TableId(type = IdType.AUTO) private Long id; private String name; private Integer age; @Version // 版本号字段 private Integer version; } 开启 Mybatis-Plus 乐观锁插件 在 MybatisPlusConfig 配置类中启用 乐观锁插件: @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } } 更新时,Mybatis-Plus 自动维护版本号 @Autowired private UserMapper userMapper; public void updateUserAge(Long userId) { User user = userMapper.selectById(userId); user.setAge(user.getAge() + 1); userMapper.updateById(user); // Mybatis-Plus 会自动带上 version 字段 }

如果 version 发生变化,更新失败,需要重新读取数据再更新。


2.2 悲观锁

适用场景:适用于 写多读少、强一致性 场景,例如 金融交易、订单扣款 等。

实现方式:

SELECT … FOR UPDATE:在事务内查询数据并加锁,防止其他事务修改数据。使用数据库本身的行锁(Row Lock)。

示例:使用 FOR UPDATE 进行悲观锁控制

@Select("SELECT * FROM user WHERE id = #{id} FOR UPDATE") User selectForUpdate(Long id); 事务提交前,其他事务无法修改该行数据。适用于事务范围内需要严格一致性的操作。

缺点:

如果锁住的数据较多,会导致 大量事务等待,影响并发能力。
3. Mybatis-Plus 高并发优化实践 3.1 批量插入

在高并发写入场景下,逐条 INSERT 可能会导致 SQL 频繁执行,影响性能。Mybatis-Plus 提供了 批量插入 的方式:

@Autowired private UserMapper userMapper; public void batchInsertUsers(List<User> users) { userMapper.insertBatchSomeColumn(users); }

注意:insertBatchSomeColumn 需要开启 Mybatis-Plus 扩展插件。


3.2 避免 N+1 查询

问题:当查询列表数据时,可能会引发多次 SQL 查询:

List<Order> orders = orderMapper.selectList(null); for (Order order : orders) { User user = userMapper.selectById(order.getUserId()); }

解决方案:

使用 IN 查询 一次性获取所有用户数据: List<Long> userIds = orders.stream().map(Order::getUserId).collect(Collectors.toList()); List<User> users = userMapper.selectBatchIds(userIds); 使用 Mybatis-Plus 关联查询 @Select("SELECT o.*, u.name as userName FROM orders o JOIN user u ON o.user_id = u.id WHERE o.id = #{orderId}") OrderWithUser selectOrderWithUser(Long orderId);
4. 数据库连接池优化

数据库连接池(DataSource)是高并发优化的核心组件,推荐使用 Druid 或 HikariCP。

4.1 HikariCP 连接池优化

在 application.yml 配置:

spring: datasource: url: jdbc:mysql://localhost:3306/test username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver hikari: minimum-idle: 10 maximum-pool-size: 50 idle-timeout: 30000 max-lifetime: 1800000 connection-timeout: 3000

参数解析:

maximum-pool-size: 连接池最大连接数,通常设置为 CPU 核心数 * 2 + 1。minimum-idle: 最小空闲连接数。connection-timeout: 获取连接的超时时间(建议不超过 3 秒)。max-lifetime: 连接最大存活时间,防止长时间占用连接。
5. 总结 优化点方法适用场景并发控制乐观锁 @Version读多写少,如库存扣减悲观锁SELECT ... FOR UPDATE高一致性,如订单扣款批量插入insertBatchSomeColumn()大批量数据插入避免 N+1 查询IN 查询、Mybatis-Plus 关联查询避免多次查询连接池优化HikariCP提高数据库连接管理效率

在高并发场景下,数据库优化是一个系统性工程。合理选择 乐观锁/悲观锁、批量插入、数据库连接池优化,可以极大提高数据库吞吐能力,确保系统在高并发下依然稳定高效!🚀

标签:

高并发场景下的数据库优化由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“高并发场景下的数据库优化