はじめに
こちらの記事でMybatis Generatorのpluginを作成して、特定カラムをデフォルト値で更新する方法を紹介しましたが、同じようにpluginを作成して、selectByPrimaryKeyForUpdate
メソッドを追加し、PKでレコード取得時にFOR UPDATE
句を追加する方法を紹介します。
準備
プラグインの作成方法は以下で説明してるのでプラグイン作成のための準備事項やプラグインの実行方法はこちらを参照してください。
やり方
PluginAdapterのサブクラスの実装
package com.example.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.mybatis.generator.api.FullyQualifiedTable;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
/**
* selectByPrimaryKeyに、排他取得用の"FOR UPDATE"句を追加するためのプラグイン
*/
public class AddForUpdatePlugin extends PluginAdapter {
private final Map<FullyQualifiedTable, List<XmlElement>> elementsToAdd = new HashMap<>();
@Override
public boolean validate(List<String> warnings) {
return true;
}
@Override
public boolean sqlMapSelectByPrimaryKeyElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
// ForUpdate用の新しいタグを生成
XmlElement newElement = new XmlElement(element);
Iterator<Attribute> iterator = newElement.getAttributes().iterator();
while (iterator.hasNext()) {
Attribute attribute = iterator.next();
if ("id".equals(attribute.getName())) {
iterator.remove();
Attribute newAttribute = new Attribute("id", attribute.getValue() + "ForUpdate");
newElement.addAttribute(newAttribute);
// "for update"を追加
newElement.addElement(new TextElement("for update"));
break;
}
}
// 新しく生成したタグをローカル変数に保存。後ほどsqlMapDocumentGeneratedメソッドにてRootDocument配下に追加
List<XmlElement> elements = elementsToAdd.computeIfAbsent(introspectedTable.getFullyQualifiedTable(),
k -> new ArrayList<>());
elements.add(newElement);
return true;
}
@Override
public boolean clientSelectByPrimaryKeyMethodGenerated(Method method, Interface interfaze,
IntrospectedTable introspectedTable) {
// 新しいメソッドを追加
Method newMethod = new Method(method);
newMethod.setName(method.getName() + "ForUpdate");
interfaze.addMethod(newMethod);
return true;
}
@Override
public boolean sqlMapDocumentGenerated(Document document,
IntrospectedTable introspectedTable) {
List<XmlElement> elements = elementsToAdd.get(introspectedTable.getFullyQualifiedTable());
if (elements != null) {
for (XmlElement element : elements) {
document.getRootElement().addElement(element);
}
}
return true;
}
}
sqlMapSelectByPrimaryKeyElementGenerated()
メソッドをオーバーライドしてSQL定義用XMLファイルのselectByPrimaryKey
をベースにselectByPrimaryKeyForUpdate
用のDOMを新たに生成、生成したDOMにfor update
句を追加します。
sqlMapDocumentGenerated()
メソッドをオーバーライドして、sqlMapSelectByPrimaryKeyElementGenerated()
メソッドにて生成したDOMをXMLに追加します。
さらに、clientSelectByPrimaryKeyMethodGenerated()
メソッドオーバーライドして、MapperクラスのselectByPrimaryKey
メソッドをベースにselectByPrimaryKeyForUpdate
メソッドを作成します。
generatorConfig.xmlに作成したプラグインを設定
<generatorConfiguration>
<context id=...>
<!-- 排他取得用の"FOR UPDATE"句を追加するためのプラグイン -->
<plugin type="com.example.test.AddForUpdatePlugin"/>
...
generatorConfig.xmlに上記で作成したクラスをplugin
タグに設定します。
生成されたファイルのサンプル
...
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table public.user
*
* @mbg.generated Mon May 12 14:43:50 JST 2025
*/
User selectByPrimaryKeyForUpdate(String userId);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table public.user
*
* @mbg.generated Mon May 12 14:43:50 JST 2025
*/
User selectByPrimaryKey(String userId);
...
上記の通り、selectByPrimaryKeyForUpdate()
メソッドが追加で生成されます。
...
<select id="selectByPrimaryKeyForUpdate" parameterType="java.lang.String" resultMap="BaseResultMap">
<!--
WARNING - @mbg.generated
This element is automatically generated by MyBatis Generator, do not modify.
This element was generated on Mon May 12 14:43:50 JST 2025.
-->
select
<include refid="Base_Column_List" />
from public.user
where user_id = #{userId,jdbcType=VARCHAR}
for update
</select>
...
上記の通り、selectByPrimaryKeyForUpdate
が生成され、最後にforupdate
が出力されていま。
参考サイト