# [Know Issues] Unknown prepare statement handler

## Key Words

Unknown prepare statement handler, prepared statement not found

## Description

使用 JDBC Loadbalance 连接 TiDB 数据库并且配置 cachePrepStmts=true，当前 MySQL JDBC 版本是 5.1.49。在 TiDB 的日志中偶尔会有如下日志打印：

```log
[2022/08/31 09:52:59.340 +08:00] [Info] [conn.go:877] ["command dispatched failed"] [conn=38137] [connInfo="id:38137, addr:xxx.xxx.xxx.xxx:1149 status:0, collation:utf8_general_ci, user:param"] [command=Execute] [status="inTxn:0, autocommit:0"] [sql="prepared statement not found, ID: 20"] [txn_mode=PESSIMISTIC] [err="ERROR 1243 (HY000): Unknown prepared statement handler (%!(BADPREC)stmt_execute) given to %!s(MISSING)"]
```

## Root Cause

JDBC 驱动库在 cachePrepStmts=true 的时候，客户端会缓存 prepare stmt 的结果。如果发现相同 SQL 语句则跳过 STMT_PREPARE 直接使用上一次返回的 stmt ID。如果跨了 load balance 使用，就会导致在 tidb A 上面 prepare stmt id 发到 tidb B 上面，进而找不到 stmt id 而报错 unknown prepare stmatement handler。

## Diagnostic Steps

1. 先找到报错 SQL 相关的日志,成功的时候的流程是：
   1. 先执行 set autocommit = 0 
   2. 再执行 STMT_PREPARE，sql="update table 
   3. 再执行 STMT_EXECUTE 
   4. commit / autocommit=1
   
   而失败的那一次，它执行的是 autocommit=0 之后的下一步，没有 STMT_PREPARE，直接执行了 STMT_EXECUTE。
2. 使用 JDBC 连接 tidb 数据库并且配置 cachePrepStmts=true。
3. 通过 JDBC 内置的 load balance 负载均衡连接多个 TiDB 实例。

## Resolution

N/A

## Workaround

两种方式:

1. JDBC 客户端处理，建议不要客户端缓存 prepare 结果。
2. 建议不要用 JDBC 内置的 load balance 功能连接 TiDB。

## Affected Versions

ALL
