MyBatis 透過 JDBC 的 `Statement.getGeneratedKeys()` 取得資料庫自增主鍵,並自動回寫到實體或 Map 的指定屬性中。
<insert id="insertOrder" useGeneratedKeys="true" keyProperty="id"
parameterType="com.example.model.Orders">
insert into orders
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="number != null">order_number,</if>
<if test="orderTime != null">order_time,</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="number != null">#{number},</if>
<if test="orderTime != null">#{orderTime},</if>
</trim>
</insert>
public interface OrderMapper {
/** 回傳值為影響行數,主鍵已回寫到 order 物件的 id 欄位 */
int insertOrder(Orders order);
}
public class Orders {
private Long id; // 自增主鍵,插入後自動回寫
private String number;
private Date orderTime;
// getter/setter 省略
}
@Service
public class OrderService {
@Autowired OrderMapper orderMapper;
public Long createOrder(Orders order) {
int rows = orderMapper.insertOrder(order);
if (rows > 0) {
return order.getId(); // 直接獲取回寫的主鍵
}
throw new RuntimeException("插入失敗");
}
}
<insert id="insertMap" useGeneratedKeys="true" keyProperty="id" parameterType="map">
insert into orders (order_number, order_time) values (#{number}, #{orderTime})
</insert>
public int insertMap(Map<String, Object> params);
// 調用
Map<String, Object> params = new HashMap<>();
params.put("number", "ORD-001");
params.put("orderTime", new Date());
mapper.insertMap(params);
Long id = (Long) params.get("id"); // 從 Map 取回主鍵
若主鍵非自增(如 UUID、序列、複合鍵),改用 `
<insert id="insertWithSeq">
<selectKey keyProperty="id" resultType="long" order="BEFORE">
select nextval('order_seq') -- PostgreSQL 序列
-- select seq_order.nextval from dual -- Oracle
</selectKey>
insert into orders (id, order_number) values (#{id}, #{number})
</insert>
| 現象 | 原因 | 解決 |
|---|---|---|
| id 仍為 null | 資料表主鍵未設 AUTO_INCREMENT | 檢查 DDL:`id bigint auto_increment primary key` |
| keyProperty 拼錯 | 實體欄位名不一致(如 `orderId` vs `id`) | 確保 `keyProperty` 對應實體確切欄位名 |
| 批次插入無回寫 | MyBatis `ExecutorType.BATCH` 不支援 getGeneratedKeys | 改用 `ExecutorType.SIMPLE` 或逐條插入 |
| PostgreSQL serial 型別 | 需指定 `keyColumn="id"` | 加上 `keyColumn` 屬性指定主鍵欄位名 |
善用 `useGeneratedKeys`,讓資料庫負責主鍵生成,應用層零負擔獲取 ID,是 MyBatis 最實用的「小而美」功能之一。