TiDB 最佳实践:Java 应用开发全攻略
docs-cn TiDB/TiKV/PD 中文文档 项目地址: https://gitcode.com/gh_mirrors/do/docs-cn
前言
作为一款兼容 MySQL 协议的新型分布式数据库,TiDB 在 Java 生态中的使用越来越广泛。本文将全面剖析 Java 应用与 TiDB 交互时的最佳实践,帮助开发者规避常见陷阱,充分发挥 TiDB 的性能优势。
一、Java 应用数据库架构全景
典型的 Java 应用数据库访问架构包含以下关键组件:
- 通信协议层:基于标准 MySQL 协议与 TiDB 交互
- JDBC 驱动层:MySQL Connector/J 或 MariaDB Connector/J 实现
- 连接池层:HikariCP、Druid 等连接池管理
- ORM 框架层:MyBatis、Hibernate 等数据访问框架
- 事务管理层:Spring Transaction 等事务控制
- 业务逻辑层:应用核心业务代码
理解各层的作用和交互方式,是优化 Java 应用与 TiDB 交互的基础。
二、JDBC 深度优化指南
2.1 核心 API 选择策略
预处理语句(PreparedStatement)
最佳实践:
- 始终使用 PreparedStatement 而非 Statement
- 配合
useServerPrepStmts=true
启用服务端预处理 - 配置
cachePrepStmts=true
缓存预处理语句
原理:预处理语句可避免重复解析 SQL,显著提升 OLTP 场景性能。
批量操作(Batch)
最佳实践:
- 使用
addBatch()/executeBatch()
进行批量操作 - 必须配置
rewriteBatchedStatements=true
- 对于大批量操作,建议分批执行(如每批 1000 条)
效果:能将 INSERT INTO t VALUES(1);INSERT INTO t VALUES(2)
改写为 INSERT INTO t VALUES(1),(2)
,减少网络往返。
流式结果集(StreamingResult)
最佳实践:
- 处理大结果集时设置
FetchSize=Integer.MIN_VALUE
- 或使用 Cursor Fetch 模式(需
useCursorFetch=true
)
对比:
- 流式模式:内存占用低,性能更好
- Cursor Fetch:TiDB 需先加载全部数据,内存压力大
2.2 关键连接参数配置
推荐的基础配置模板:
jdbc:mysql://host:port/db?
useServerPrepStmts=true&
cachePrepStmts=true&
prepStmtCacheSize=1000&
prepStmtCacheSqlLimit=2048&
rewriteBatchedStatements=true&
useConfigs=maxPerformance&
characterEncoding=UTF-8&
useSSL=false
参数详解:
-
预处理优化组:
useServerPrepStmts
:启用服务端预处理cachePrepStmts
:客户端缓存预处理语句prepStmtCacheSize
:缓存语句数量(默认25)prepStmtCacheSqlLimit
:缓存语句长度限制(默认256)
-
批量优化组:
rewriteBatchedStatements
:批量语句重写
-
性能优化组:
useConfigs=maxPerformance
:禁用无用查询
-
超时控制组:
sessionVariables=wait_timeout=3600
:空闲超时1小时sessionVariables=max_execution_time=300000
:查询超时5分钟
三、连接池优化实践
3.1 连接池选型建议
推荐使用 HikariCP,其特点包括:
- 轻量高效,性能最优
- 完善的监控指标
- 活跃连接自动均衡
3.2 HikariCP 配置模板
hikari:
maximumPoolSize: 20 # 建议为CPU核数4-10倍
connectionTimeout: 30000 # 获取连接超时(毫秒)
maxLifetime: 1200000 # 连接最大存活时间(毫秒)
keepaliveTime: 120000 # 保活检测间隔(毫秒)
关键参数说明:
maximumPoolSize
不宜过大,避免TiDB资源浪费maxLifetime
应小于TiDB的wait_timeout
keepaliveTime
防止中间件断开空闲连接
四、MyBatis 优化技巧
4.1 SQL 映射优化
参数绑定方式:
<!-- 推荐使用#{}预处理方式 -->
<select id="findUser" resultType="User">
SELECT * FROM users WHERE id = #{userId}
</select>
<!-- 避免${}文本替换方式 -->
<select id="findUser" resultType="User">
SELECT * FROM users WHERE id = ${userId}
</select>
4.2 动态批量插入
<insert id="batchInsert" parameterType="java.util.List">
INSERT INTO users (name,age) VALUES
<foreach item="item" collection="list" separator=",">
(#{item.name},#{item.age})
</foreach>
</insert>
效果:生成 INSERT INTO users(name,age) VALUES(?,?),(?,?)
形式SQL。
4.3 流式查询处理
XML 配置方式:
<select id="scanLargeData" fetchSize="-2147483648">
SELECT * FROM large_table
</select>
注解方式:
@Select("SELECT * FROM large_table")
@Options(fetchSize = Integer.MIN_VALUE)
Cursor<Data> scanLargeData();
五、Spring 事务管理
5.1 事务传播机制
@Transactional(propagation=Propagation.REQUIRED) // 默认值,支持当前事务
public void methodA() {
// ...
}
@Transactional(propagation=Propagation.REQUIRES_NEW) // 新建事务
public void methodB() {
// ...
}
注意事项:
- 避免大事务,单个事务不宜包含过多操作
- 只读查询使用
@Transactional(readOnly=true)
- 注意事务内混用读写操作可能导致连接无法释放
六、常见问题排查
6.1 连接泄露排查
症状:
- 应用逐渐变慢
- 连接数持续增长不释放
工具:
jstack
查看线程堆栈jmap + MAT
分析连接对象
6.2 性能问题诊断
步骤:
- 使用
arthas trace
跟踪慢方法 - 检查 TiDB 慢查询日志
- 分析执行计划
6.3 连接池监控
关键监控指标:
- 活跃连接数
- 空闲连接数
- 等待获取连接的线程数
- 连接获取平均耗时
七、总结
通过本文介绍的最佳实践,Java 开发者可以:
- 正确配置 JDBC 驱动,发挥 TiDB 最佳性能
- 合理使用连接池,避免连接泄露
- 优化 MyBatis 使用方式,提升数据访问效率
- 规范事务管理,避免分布式事务问题
- 掌握问题排查方法,快速定位性能瓶颈
遵循这些实践原则,Java 应用与 TiDB 的配合将更加高效稳定。
docs-cn TiDB/TiKV/PD 中文文档 项目地址: https://gitcode.com/gh_mirrors/do/docs-cn
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考