在 MyBatis 中插入數據後獲取資料庫生成的自增主鍵(ID),是極高頻的實戰需求。本文詳細解析 useGeneratedKeys 與 selectKey 兩大方案的配置、原理、適用場景與避坑指南。
INSERT INTO spares(spares_name, spares_type_id, spares_spec)
VALUES(#{name}, #{typeId}, #{spec})
Statement.getGeneratedKeys() 機制id 屬性
public class Spares {
private Long id; // 必須有 setter
private String name;
private Integer typeId;
private String spec;
// getter/setter
}
@Service
public class SparesServiceImpl implements SparesService {
@Autowired
private SparesMapper sparesMapper;
@Override
public int insert(Spares spares) {
int count = sparesMapper.insert(spares);
// 插入後,spares.getId() 即可獲取自增主鍵!
System.out.println("新增記錄 ID: " + spares.getId());
return count;
}
}
PreparedStatement,設定 Statement.RETURN_GENERATED_KEYSexecuteUpdate()getGeneratedKeys() 獲取 ResultSetkeyProperty 屬性
SELECT LAST_INSERT_ID()
INSERT INTO person(name, pswd) VALUES(#{name}, #{pswd})
LAST_INSERT_ID():返回當前連接最後生成的 AUTO_INCREMENT 值,連接級隔離,並發安全SELECT @@IDENTITY:同 LAST_INSERT_ID(),但部分場景不同| 維度 | useGeneratedKeys | selectKey (LAST_INSERT_ID) |
|---|---|---|
| 底層機制 | JDBC 3.0 標準 API | 額外 SQL 查詢 |
| 資料庫相關性 | 支援多種 DB(需驅動支援) | MySQL 專用語法 |
| 效能 | 單次往返,略優 | 額外查詢,微小開銷 |
| 複合主鍵 | 支援(keyColumn 指定多列) | 需多次 selectKey |
| 非自增主鍵 | 不支援 | 支援(BEFORE + 序列/UUID) |
| Oracle/PostgreSQL | 支援(Sequence + BEFORE) | 支援(序列 nextval) |
| 批量插入獲取 ID | 支援(MyBatis 3.4+) | 不直接支援 |
INSERT INTO spares(name, type_id, spec) VALUES
(#{item.name}, #{item.typeId}, #{item.spec})
要求:MyBatis 3.4.0+、MySQL 5.1.35+ 驅動、rewriteBatchedStatements=true 連接參數。
SELECT REPLACE(UUID(), '-', '')
INSERT INTO orders(order_no, ...) VALUES(#{orderNo}, ...)
| 現象 | 原因 | 解決 |
|---|---|---|
| ID 為 0/null | 未配置 useGeneratedKeys 或 keyProperty 錯誤 | 檢查屬性名、setter 存在性 |
| 批量插入 ID 全相同 | 驅動版本低或未開啟 rewriteBatchedStatements | 升級驅動、加連接參數 |
| 並發下 ID 錯誤 | 使用 MAX(id)+1 等非原子方式 | 必須用自增/序列/LAST_INSERT_ID |
| 事務回滾 ID 不連續 | 自增計數器不回滾(資料庫特性) | 正常現象,業務勿依賴 ID 連續 |