見出し画像

【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を返却することもできます。

この記事が気に入ったらサポートをしてみませんか?