MyBatisでDBにデータ新規登録するときに、
登録したデータのIDを返却する方法が分からなく調べたことがあるので、
メモしておきたいと思います。
前提として、Primary KeyなどオートインクリメントされるDB構造になっている想定での内容です。
https://mybatis.org/mybatis-3/ja/sqlmap-xml.html#insert_update_and_delete
検証環境・バージョン
- MacOS:Sonoma 14.6
- Amazon Corretto:17
- SpringBoot:3.4.0
- MyBatis:3.0.4
- MyBatis generator-core:1.4.0
- IntelliJ IDEA:2024.2 (Ultimate Edition)
useGeneratedKeys オプション
MyBatisは、XMLタグで実行SQLを定義したり、
アノテーションでSQL実行処理を実装することができます。
INSERT処理実装箇所で、useGeneratedKeys=trueというオプションを指定すると、
INSERTを実行したデータのIDを取得することができます。
- アノテーションで指定する例
@Insert("insert into user (name, age) values (#{name}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertUserReturnId(User user);
- XMLタグで指定する例
<insert id="insertUserReturnIdXml" parameterType="example.com.springboot_mybatis.model.User" useGeneratedKeys="true" keyProperty="id">
insert into user (name, age)
values (#{name}, #{age})
</insert>
モデルクラス利用例
モデルクラスをINSERT処理に引数として渡してIDを取得する例です。
package example.com.springboot_mybatis.model;
public class User {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
package example.com.springboot_mybatis.service;
import example.com.springboot_mybatis.model.User;
import example.com.springboot_mybatis.mapper.UserMapperCustom;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class UserService {
@Autowired
private UserMapperCustom userMapperCustom;
@Transactional(readOnly = false)
public Integer insertUserSample1() {
User user = new User();
user.setName("User1");
user.setAge(30);
userMapperCustom.insertUserReturnId(user);
return user.getId(); // 生成されたデータのIDが返却される
}
@Transactional(readOnly = false)
public Integer insertUserSample2() {
User user = new User();
user.setName("User2");
user.setAge(40);
userMapperCustom.insertUserReturnIdXml(user);
return user.getId(); // 生成されたデータのIDが返却される
}
}
package example.com.springboot_mybatis.mapper;
import example.com.springboot_mybatis.model.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
public interface UserMapperCustom {
// INSERT処理 アノテーション実装例
@Insert("insert into user (name, age) values (#{name}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertUserReturnId(User user);
// INSERT処理 XML実装例
void insertUserReturnIdXml(User user);
}
<!-- INSERT処理 XML実装例 -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="example.com.springboot_mybatis.mapper.UserMapperCustom">
<insert id="insertUserReturnIdXml" parameterType="example.com.springboot_mybatis.model.User" useGeneratedKeys="true" keyProperty="id">
insert into user (name, age)
values (#{name}, #{age})
</insert>
</mapper>
利用するモデルクラスは、自動生成で作成したモデルクラス等でも実装可能です。
Mapパラメータ受取例
INSERTの実装オプションとしてkeyProperty=”Mapキー”を指定すると、
新規登録されたデータの一部をMap形式で受け取ることができます。
package example.com.springboot_mybatis.service;
import example.com.springboot_mybatis.model.User;
import example.com.springboot_mybatis.mapper.UserMapperCustom;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class UserService {
@Transactional(readOnly = false)
public Integer insertUserSample3() {
Map<String, Object> idMap = new HashMap<>();
userMapperCustom.insertUserReturnIdMap("User3", 50, idMap);
BigInteger id = (BigInteger) idMap.get("id"); // 生成されたデータのIDが返却される
return id.intValue();
}
@Transactional(readOnly = false)
public Integer insertUserSample4() {
Map<String, Object> idMap = new HashMap<>();
userMapperCustom.insertUserReturnIdMapXml("User3", 50, idMap);
BigInteger id = (BigInteger) idMap.get("id"); // 生成されたデータのIDが返却される
return id.intValue();
}
}
package example.com.springboot_mybatis.mapper;
import example.com.springboot_mybatis.model.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
public interface UserMapperCustom {
// INSERT処理 アノテーション実装例
@Insert("insert into user (name, age) values (#{name}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "idMap.id")
void insertUserReturnIdMap(@Param("name") String name, @Param("age") int age, @Param("idMap") Map<String, Object> idMap);
// INSERT処理 XML実装例
void insertUserReturnIdMapXml(@Param("name") String name, @Param("age") int age, @Param("idMap") Map<String, Object> idMap);
}
<!-- INSERT処理 XML実装例 -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="example.com.springboot_mybatis.mapper.UserMapperCustom">
<insert id="insertUserReturnIdMapXml" parameterType="map" useGeneratedKeys="true" keyProperty="idMap.id">
insert into user (name, age)
values (#{name}, #{age})
</insert>
</mapper>
[補足] 次に採番されるIDを取得する
PostgreSQLの実装例
PostgreSQLの場合、nextval
関数で次に採番されるIDを取得できます。
アノテーション実装、XML実装のどちらでも取得できます。
package example.com.springboot_mybatis.mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;
@Component
public interface UserMapperCustom {
@Select("SELECT nextval('user_id_seq')")
Integer getNextSequenceId();
}
<mapper namespace="example.com.springboot_mybatis.mapper.UserMapperCustom">
<select id="getNextSequenceId" resultType="java.lang.Integer">
SELECT nextval('user_id_seq')
</select>
</mapper>
MySQLの実装例
<mapper namespace="example.com.springboot_mybatis.mapper.UserMapperCustom">
<select id="getNextAutoIncrementId" resultType="java.lang.Integer">
SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'your_database_name'
AND TABLE_NAME = 'user'
</select>
</mapper>
今回のメモは以上となります。
MyBatisはあまり利用したことがなく、
基本的な機能なども把握できていなかったりしますので、
調べた際にはメモしておきたいと思います。