doilux’s tech blog

ITに関する備忘録。 DDP : http://doiluxng.hatenablog.com/entry/2018/01/01/195409

Mybatisでauto_incrementされた値を取得する方法

insertの戻り値で取得する方法があると思ってたんですが、mutableなクラスにセットさせる方法しかなかったです。 まずはIDをセットするためのクラスを作り

class GeneratedEmployeeId {
    var value: Int? = null

    fun setValue(v: Int) {
        value = v
    }

    fun convert(): EmployeeId {
        Objects.requireNonNull(value, "generated employee-id is null")
        return EmployeeId(value!!)
    }
}

@SelectKeyを使って、引数に渡したGeneratedEmployeeIdにセットするように指定します。

@Mapper
interface EmployeeTableMapper {

    /**
     * Insert register event to register_event table
     *
     * @param event
     */
    @Insert("""
    insert into employee_register_events (
        first_name
        , last_name
        , salary
    ) values (
        #{event.firstName}
        , #{event.lastName}
        , #{event.salary})
""")
    @SelectKey(
            statement = arrayOf("select @@IDENTITY"),
            before = false,
            resultType = Int::class,
            keyProperty = "genId.value",
            keyColumn = "id"
    )
    fun insert(@Param("event") event: EmployeeRegisterEvent, @Param("genId") genId: GeneratedEmployeeId)
}

テストしてみます。なんどもinsertを動かしたのでidは8まで払い出しています。

mysql> select * from employee_register_events;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
|  1 | shown      | white     | 200000 |
|  2 | shown      | white     | 200000 |
|  3 | shown      | white     | 200000 |
|  4 | shown      | white     | 200000 |
|  5 | shown      | white     | 200000 |
|  6 | shown      | white     | 200000 |
|  7 | shown      | white     | 200000 |
|  8 | shown      | white     | 200000 |
+----+------------+-----------+--------+
8 rows in set (0.00 sec)

このテストはコケるはず(次に払い出される値は9なので)

@SpringBootTest
class EmployeeTableMapperTest extends Specification {

    @Autowired
    private EmployeeTableMapper sut

    def "test"() {
        expect:
        def genId = new GeneratedEmployeeId()
        sut.insert(new EmployeeRegisterEvent("shown", "white", 200000), genId)
        genId.getValue() == 1
    }
}

想定通りこけてくれました。

Condition not satisfied:

genId.getValue() == 1
|     |          |
|     9          false
work.doilux.dddsamplekotlin.ftth.hr.GeneratedEmployeeId@2233cac0

Expected :1

Actual   :9

mutableなクラスを作るのは微妙なので、Oracle(ポスグレも?)ならシーケンスにselectかけて取り出した方がいいと思います。 MySQLの場合はシーケンスがないので、どうしてもImmutableにしたいなら採番テーブルを作るしかなさそう。 MySQLにシーケンスが欲しいなあ。