开发 Java 应用使用 TiDB 的最佳实践
本文主要介绍如何开发 Java 应用程序以更好地使用 TiDB,包括开发中的常见问题与最佳实践。
Java 应用中的数据库相关组件
通常 Java 应用中和数据库相关的常用组件有:
- 网络协议:客户端通过标准 MySQL 协议和 TiDB 进行网络交互。
- JDBC API 及实现:Java 应用通常使用 JDBC (Java Database Connectivity) 来访问数据库。JDBC 定义了访问数据库 API,而 JDBC 实现完成标准 API 到 MySQL 协议的转换,常见的 JDBC 实现是 MySQL Connector/J,此外有些用户可能使用 MariaDB Connector/J。
- 数据库连接池:为了避免每次创建连接,通常应用会选择使用数据库连接池来复用连接,JDBC DataSource 定义了连接池 API,开发者可根据实际需求选择使用某种开源连接池实现。
- 数据访问框架:应用通常选择通过数据访问框架 (MyBatis, Hibernate) 的封装来进一步简化和管理数据库访问操作。
- 业务实现:业务逻辑控制着何时发送和发送什么指令到数据库,其中有些业务会使用 Spring Transaction 切面来控制管理事务的开始和提交逻辑。

如上图所示,应用可能使用 Spring Transaction 来管理控制事务非手工启停,通过类似 MyBatis 的数据访问框架管理生成和执行 SQL,通过连接池获取已池化的长连接,最后通过 JDBC 接口调用实现通过 MySQL 协议和 TiDB 完成交互。
接下来将分别介绍使用各个组件时可能需要关注的问题。
JDBC
Java 应用尽管可以选择在不同的框架中封装,但在最底层一般会通过调用 JDBC 来与数据库服务器进行交互。对于 JDBC,需要关注的主要有:API 的使用选择和 API Implementer 的参数配置。
JDBC API
对于基本的 JDBC API 使用可以参考 JDBC 官方教程,本文主要强调几个比较重要的 API 选择。
使用 Prepare API
对于 OLTP 场景,程序发送给数据库的 SQL 语句在去除参数变化后都是可穷举的某几类,因此建议使用预处理语句 (Prepared Statements) 代替普通的文本执行,并复用预处理语句来直接执行,从而避免 TiDB 重复解析和生成 SQL 执行计划的开销。
目前多数上层框架都会调用 Prepare API 进行 SQL 执行,如果直接使用 JDBC API 进行开发,注意选择使用 Prepare API。
另外需要注意 MySQL Connector/J 实现中默认只会做客户端的语句预处理,会将 ? 在客户端替换后以文本形式发送到服务端,所以除了要使用 Prepare API,还需要在 JDBC 连接参数中配置 useServerPrepStmts = true,才能在 TiDB 服务器端进行语句预处理(下面参数配置章节有详细介绍)。