Mybatisがプライマリ・キー機能を同時に返す2つの方法を追加


Mybatisはプライマリ・キー機能を追加して返します
本人はMybatis 3.Xのバージョンを使用しています
公式ドキュメントには、次の2つの方法があります.
  • useGeneratedKeys:(insertとupdateのみで使用)これにより、データベース内で生成されたプライマリ・キー(たとえば、MySQLやSQLサーバのようなリレーショナル・データベース管理システムの自動インクリメント・フィールド)を取り出すには、JDBCのgetGeneratedKeysメソッドを使用します.デフォルト値はfalseです.データベースがプライマリ・キーを自動的に生成するフィールド(MySQLやSQL Serverなど)をサポートしている場合は、useGeneratedKeys="true"を設定してkeyPropertyをターゲット・プロパティに設定すればOKです.
  • データベースがプライマリ・キーを自動的に生成するフィールドをサポートしていない場合.サブラベルを使用して実装できます.


  • エンティティクラスとmapperインタフェースレイヤのコードを省略し、xmlファイルのコードのみを例として示します.
    <mapper namespace="com.mirt.mybatis_demo.mapper.AutoIncrementMapper">
    
        <resultMap id="BaseResult" type="com.mirt.mybatis_demo.entity.AutoIncrementEntity">
            <result column="id" property="id"/>
            <result column="comment" property="comment"/>
            <result column="create_time" property="createTime"/>
        resultMap>
    
        <insert id="saveOneByUseGeneratedKeys" useGeneratedKeys="true" keyProperty="id">
            insert into auto_increment_table (comment, create_time) values (#{comment},now());
        insert>
    
        <insert id="saveOneBySelectKey" parameterType="com.mirt.mybatis_demo.entity.AutoIncrementEntity">
            <selectKey resultType="int" order="AFTER" keyProperty="id">
                SELECT LAST_INSERT_ID();
            selectKey>
            insert into auto_increment_table (comment, create_time) values (#{comment},now());
        insert>
    mapper>
    

    ここでは、2つの方法saveOneByUseGeneratedKeyssaveOneBySelectKeyを定義し、公式に与えられた2つの方法が実行可能であるかどうかを示す.
    テストクラスの下での方法と結果を示します.
    	@Test
        public void saveOneByUseGeneratedKeys() {
            AutoIncrementEntity aie = new AutoIncrementEntity();
            aie.setComment("useGeneratedKeys");
            boolean res = autoIncrementMapper.saveOneByUseGeneratedKeys(aie) > 0;
            if (res) {
                System.out.println(aie);
            }else {
                System.out.println("insert fail");
            }
        }
    
        @Test
        public void saveOneBySelectKey() {
            AutoIncrementEntity aie = new AutoIncrementEntity();
            aie.setComment("selectKey");
            boolean res = autoIncrementMapper.saveOneByUseGeneratedKeys(aie) > 0;
            if (res) {
                System.out.println(aie);
            }else {
                System.out.println("insert fail");
            }
        }
    

    結果は
    {id:1}
    {id:2}
    

    確かに自己増加のプライマリ・キーが返されていることがわかります.
    ソースコード
    package org.apache.ibatis.executor.keygen;
    
    import java.sql.Statement;
    import org.apache.ibatis.executor.Executor;
    import org.apache.ibatis.mapping.MappedStatement;
    
    public interface KeyGenerator {
        void processBefore(Executor var1, MappedStatement var2, Statement var3, Object var4);
    
        void processAfter(Executor var1, MappedStatement var2, Statement var3, Object var4);
    }
    

    mybatisのKeyGeneratorインタフェースは、2つの方法を提供しています.1つは、実行前が実行後であり、上記の例では、プライマリ・キーは挿入後に得られるため、processAfterという方法が使用されています.
    このインタフェースには3つの実装クラスがあり、デフォルトではJdbc3KeyGeneratorという実装クラスが使用されています.
    	public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
            this.processBatch(ms, stmt, this.getParameters(parameter));
        }
    
        public void processBatch(MappedStatement ms, Statement stmt, Collection<Object> parameters) {
            ResultSet rs = null;
    
            try {
                rs = stmt.getGeneratedKeys();
                Configuration configuration = ms.getConfiguration();
                TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
                String[] keyProperties = ms.getKeyProperties(); //       keyproperties
                ResultSetMetaData rsmd = rs.getMetaData();
                TypeHandler<?>[] typeHandlers = null;
                MetaObject metaParam;
                if (keyProperties != null && rsmd.getColumnCount() >= keyProperties.length) {
                    for(Iterator var10 = parameters.iterator(); var10.hasNext(); this.populateKeys(rs, metaParam, keyProperties, typeHandlers)) {
                        Object parameter = var10.next();
                        if (!rs.next()) {
                            break;
                        }
    
                        metaParam = configuration.newMetaObject(parameter);
                        if (typeHandlers == null) {
                            typeHandlers = this.getTypeHandlers(typeHandlerRegistry, metaParam, keyProperties, rsmd);
                        }
                    }
                }
            } catch (Exception var20) {
                throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + var20, var20);
            } finally {
                if (rs != null) {
                    try {
                        rs.close();
                    } catch (Exception var19) {
                        ;
                    }
                }
    
            }
    
        }
        
        //                 
      	private void populateKeys(ResultSet rs, MetaObject metaParam, String[] keyProperties, TypeHandler<?>[] typeHandlers) throws SQLException {
            for(int i = 0; i < keyProperties.length; ++i) {
                String property = keyProperties[i];
                TypeHandler<?> th = typeHandlers[i];
                if (th != null) {
                    Object value = th.getResult(rs, i + 1);
                    metaParam.setValue(property, value);
                }
            }
    
        }
    

    mybatisの公式ドキュメントでは、keyPropwetyについて次のように説明されています.
    (insertとupdateでのみ使用可能)一意に1つの属性をマークします.MyBatisはgetGeneratedKeysの戻り値またはinsert文のselectKeysサブ要素でキー値を設定します.デフォルト:unset.複数の生成されたカラムを取得する場合は、カンマで区切られたプロパティ名のリストでも構いません.
    ソースコードからkeyPropertyも確かに複数の設定をサポートし、挿入操作の前後に統一的に格納することができることが分かった.
    プライマリ・キーにsetterメソッドがない場合は、ここでエラーが発生することに注意してください.mybatisは生成したプライマリ・キー情報をエンティティ・クラスに戻すことができません.