0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Mybatis Generatorで生成されるSQLに排他取得用FOR UPDATE句を追加する方法

Posted at

はじめに

こちらの記事でMybatis Generatorのpluginを作成して、特定カラムをデフォルト値で更新する方法を紹介しましたが、同じようにpluginを作成して、selectByPrimaryKeyForUpdateメソッドを追加し、PKでレコード取得時にFOR UPDATE句を追加する方法を紹介します。

準備

プラグインの作成方法は以下で説明してるのでプラグイン作成のための準備事項やプラグインの実行方法はこちらを参照してください。

やり方

PluginAdapterのサブクラスの実装

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に作成したプラグインを設定

generatorConfig.xml
<generatorConfiguration>
  <context id=...>
	<!-- 排他取得用の"FOR UPDATE"句を追加するためのプラグイン -->
	<plugin type="com.example.test.AddForUpdatePlugin"/>
    ...


generatorConfig.xmlに上記で作成したクラスをpluginタグに設定します。

生成されたファイルのサンプル

Mapperクラス
...

    /**
     * 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()メソッドが追加で生成されます。

SQL定義用xml
...
  <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が出力されていま。

参考サイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?