【Java+MyBatis】データ登録系API作成時に、登録に成功したレコードの、自動採番で付与されるIDを返却する
「このデータを登録しておくれ」「はいよ、登録したよ、レコード番号〇〇番として登録できたよ」というAPIを作る際、肝心の「レコード番号〇〇番として登録できたよ」をどうやって取得しようか。というお話。
レコード番号は通常自動採番に設定する
じゃないですか。いちいち最新のレコード番号取得して+1してとかしないじゃないですか。あんまり。
でも、SQLでInsertする処理は登録処理をするだけで、「今まさに登録したこのレコードで自動採番された番号はこちらです」は返してくれないじゃないですか。
それをどうやって返却すればいいのか。
引数のオブジェクトにマッピングして返す
この方法だと引数で渡すオブジェクトがイミュータブルにならないうえに関数に副作用が生じるので、ちょっと……大分スマートじゃないんですけどォ…とりあえず用事は足りるのでこの方法でやってみます。
以下のような登録情報を取り扱うクラスを用意して、ID欄を用意しておきます。
// IDとユーザー名フィールドを持つUserクラスを作る
package com.sample.PROJECT.domain.model.User;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class User{
long id=0;
String name="";
}
このプログラムはAPIとしてふるまう前提ですので、コントローラー層でPOSTのBODYとしてユーザー名を受け取るようにしておきます。
(この辺の処理はサンプルコードのコピペで作ってしまったので、具体的に何が起きているのかよくわからないんですが、コントローラーでうまいこと受け取れば、送られてきた項目にIDが無くても問題なく受け取れます。ignoreUnknown = trueのおかげな気がします。)(このあたりは使っているフレームワークとかとの兼ね合いもあるので、なんかうまいこと受け取ってください)
で、Mapper.java(上記の記事で言うところのRepository)とMappper.xmlを作ります。ここはMyBatis使うので、MyBatisのいろいろはこの辺を読んでいただいて
package com.example.PROJECT.infrastructure.datasorce.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.sample.PROJECT.domain.model.User.User;
@Mapper
public interface UserMapper{
long insertUserId(@Param("user") User user);
boolean insertUser(@Param("user") User user);
}
insertの引数に@Paramが付いてるのはSpringフレームワーク用です
こんな感じで、insertメソッドがUserクラスのインスタンスを引数に取るようにMapperを定義しておいて、Xml側でSQL文を書きます。
insertUserIdはuser_idテーブルにidだけ突っ込む用、insertUserはその後詳細情報をuserテーブルに入れる用を模しています。
で、以上の様なMapper(上記の記事でいうところのRepository)を用意して、以下の様な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="com.sample.infrastructure.datasource.User.UserMapper" >
<insert id="insertUserId" useGeneratedKeys="true" keyProperty="id">
INSERT INTO `user_id`(`user_id`) VALUES(0);
</insert>
<insert id="insertUser">
INSERT
INTO `user`(`user_id`,`name`)
VALUES(${user.id},`${user.name}`)
</insert>
</mapper>
で、Userオブジェクト渡すだけ渡して使わない、と。
いや、使ってるんですけども、裏で。
insertタグ部分でuseGeneratedKeysをtrueにして、keyPropertyに、引数として渡すオブジェクトの中の、「ここに取得したidを入れてね」というフィールドの名前を渡しておくと、自動でオブジェクト内にマッピングされます。
で、上のinsertUserIdメソッドを実行すると、その時に渡したUserオブジェクトのId欄が埋まるので、そのUserのインスタンスをそのままinsertUserメソッドに渡してあげれば、idを別のテーブルにも登録できるし、UserインスタンスからgetIdしてHTTPレスポンスとして返却すればidを返却することもできます。
この記事が気に入ったらサポートをしてみませんか?