web-dev-qa-db-ja.com

Oracle用MyBatisバッチ挿入/更新

最近、myBatisの使用方法の学習を開始しました。現在、このようなシナリオに直面しています。WebServiceを介してオブジェクトの新しいリストを常に取得する必要があります。 myBatis。

トリッキーな部分は、毎回単純にバッチ挿入を行うことができないことです。オブジェクトの一部は既にDBに存在している可能性があるためです。

私の現在のソリューションは非常に愚かで、Javaを使用して、Webサービスからオブジェクトのリストを作成し、それぞれをループし、myBatisの選択を行い、それがnullでない場合(dbにすでに存在する)、myBatisの更新を行います;それ以外の場合は、この新しいオブジェクトに対してmyBatis挿入を実行します。

機能が達成されます。しかし、私の技術リーダーは、Javaを使用してforループを実行し、1つずつ挿入/更新すると多くのシステムリソースを消費するため、非常に効率が悪いと言います。オブジェクトのリストを渡すことでmyBatisを使用します。

MyBatisでのバッチ挿入は簡単ですが、純粋に挿入するわけではないため(既存のレコードに対して更新が必要です)、ここではバッチ挿入は適切ではないと思います。私はこれのためにしばらくグーグルで調べましたが、「挿入」の代わりに「マージ」を使用する必要があるかもしれないことに気付きました(Oracleの場合)。

MyBatisでマージするためにグーグルアウトした例は、バッチではなく1つのオブジェクトのみです。したがって、専門家がMyBatisでバッチマージを行う方法に関するいくつかの例を提供できるかどうかを調べたいと思います(マッパーを書く正しい方法)?

19
Kevin

私の場合も同じシナリオがあります。ループに使用して、このレコードがデータベースに存在するかどうかを確認し、それに従って、このオブジェクトを挿入または更新のために2つの配列リストに追加しました。そして、リストするためのforループの後に挿入と更新にバッチを使用しました。

ここに元があります。異なるwhere条件に応じた更新用

1]これは更新用です

<foreach collection="attendingUsrList" item="model"  separator=";">
    UPDATE parties SET attending_user_count = #{model.attending_count}
    WHERE  fb_party_id = #{model.eid}  
</foreach>

2]これは挿入用です

<insert id="insertAccountabilityUsers" parameterType="AccountabilityUsersModel" useGeneratedKeys="false">
    INSERT INTO accountability_users 
        (
            accountability_user_id, accountability_id, to_username,
            record_status, created_by, created_at, updated_by, updated_at
        ) 
    VALUES
    <foreach collection="usersList" item="model" separator=","> 
        (           
            #{model.accountabilityUserId}, #{model.accountabilityId}, #{model.toUsername}, 
            'A', #{model.createdBy}, #{model.createdAt}, #{model.updatedBy}, #{model.updatedAt}     
        )
    </foreach>
</insert>

Daoメソッドで宣言します

void insertAccountabilityUsers(@Param("usersList") List<AccountabilityUsersModel> usersList);

更新

これが私のバッチセッションコードです

public static synchronized SqlSession getSqlBatchSession() {
    ConnectionBuilderAction connection = new ConnectionBuilderAction();
    sf = connection.getConnection();
    SqlSession session = sf.openSession(ExecutorType.BATCH);
    return session;
}

SqlSession session = ConnectionBuilderAction.getSqlSession(); 

実際、私はすでにこの質問の完全な例をここに挙げました

25
Sameer Kazi

受け入れられた答えは、バッチ操作を処理する推奨される方法ではありません。セッションを開くときにバッチエグゼキューターモードを使用する必要があるため、実際のバッチステートメントは表示されません。この post を参照してください。コード投稿者は、バッチ更新(または挿入)の適切な方法として、セッションをバッチモードで開き、単一レコードの更新(または挿入)を繰り返し呼び出すことを推奨しています。

ここに私のために働くものがあります:

public void updateRecords(final List<GisObject> objectsToUpdate) {
    final SqlSession sqlSession = MyBatisUtils.getSqlSessionFactory().openSession(ExecutorType.BATCH);
    try {
        final GisObjectMapper mapper = sqlSession.getMapper(GisObjectMapper.class);
        for (final GisObject gisObject : objectsToUpdate) {
            mapper.updateRecord(gisObject);
        }
        sqlSession.commit();
    } finally {
        sqlSession.close();
    }
}

更新/挿入でforeachを使用しないでください。また、単一レコードのみを更新/挿入するようにしてください。受け入れられた回答(無効な文字、文が終了していないなど)に従って実行すると、解決できないOracleエラーが発生しました。リンクされた投稿が示すように、受け入れられた回答に表示される更新(または挿入)は、実際には単なる巨大なSQLステートメントです。

31
rimsky