10

mybatisを新しいプロジェクトに使用することにしました。私はSQLにかなり精通しており、最近休止状態でいくつかの悪い経験をしたので、DAOへのより低レベルのアプローチを探しています。

1つを除いて、かなりいいようです。それはコレクションの処理です。

グループとユーザーの2つのPOJOがあり、それらは多対多です。コレクションを持つPOJOは、保存時にテーブル間のMM関係のみを更新する必要があるという設計哲学を決定しました。したがって、たとえば、ユーザーのコレクションを持つグループオブジェクトを保存する場合、設計哲学では、ユーザーは既に保存されている必要があり、データベースにグループとgroup_userリレーションを保存するだけで済みます。

そのため、インターフェイスのsaveGroup関数について、mybatis用に次のXMLマッピングを作成しました。

    <insert id="saveGroup" keyColumn="id"
    parameterType="se.myapp.domain.Group">
    <choose>
        <when test="id == null">
        INSERT INTO myapp_group (name, description)
        VALUES
        (#{username}, #{password});
        </when>
        <otherwise>
        UPDATE myapp_group set name=#{name}, description=#{description}
        where id=#{id};
        </otherwise>
    </choose>

    <if test="users != null">
        create temporary table tmpnewgroups (group_id integer, user_id integer);

        insert into tmpnewgroups (group_id, user_id) values (
        <foreach collection="users" item="user" open="" close="" separator="),()">
             #{id},#{user.id}
        </foreach>
        );

        insert into myapp_user_group(group_id, user_id) 
        select tmp.group_id, tmp.user_id 
        from tmpnewgroups tmp 
        left outer join myapp_user_group ug 
            on ug.group_id = tmp.group_id and ug.user_id = tmp.user_id
        where ug.group_id is null;

        delete from myapp_user_group 
        where group_id = #{id} and user_id not in (select user_id from tmpnewgroups);
    </if>

</insert>

これは意図したとおりに機能します(グループを挿入/更新し、ユーザーのコレクションをリレーションとしてデータベースに保存します)。しかし、これがベストプラクティスだとは思いません。アプリケーションは、必要に応じて休止状態に切り替えることができるように作成されているため、コレクションを保存するためのロジックは、データベース層にあることが望ましいです。mybatisには、このような操作を合理化できることに気付いていない「魔法」がありますか?

これを改善する方法について何か考えはありますか?または、アプリケーションの設計を再考し、コレクションの処理をモデルのさらに上に置く必要がありますか?

4

1 に答える 1

2

saveGroupデータマッピング操作の2番目の部分は、実際にアプリケーションの設計を再考する理由です。デルタを挿入および削除するために、メモリ内のユーザーコレクションを一時テーブルに永続化して、永続化されたテーブルと比較することは、かなり重い操作であり、グループの名前または説明だけを更新する必要がある場合は、まったく必要ありません。つまり、デルタがない場合。これが当てはまるかどうかは、現在のソリューションであるデータベースサーバー、またはアプリケーションであるデータベースクライアントによって決定できます。

グループと場合によってはそのユーザーが初めて挿入する必要がある場合とは別に、リンクテーブルを更新する必要があるかどうかをアプリケーションで判断する場合、アプリケーションは、ユーザーコレクションがその後変更されたかどうかを知る必要があります。データベースから取得されました。残念ながら、MyBatisはアプリケーションがそれを行うのを助けるつもりはありません。

ほら、Hibernateと比較すると、MyBatisはあなたのオブジェクトと、MyBatisがその仕事をした後のオブジェクトの状態、つまりオブジェクト関係マッピングではなくデータマッピングを幸いにも認識していません。Hibernateは、オブジェクトのいわゆるダーティ状態を自動的に検出できますが、MyBatisは、これがジョブの説明の一部ではなかったため、検出できません。したがって、あなたはあなた自身のデバイスに任されています。

非常に簡単なアプローチは、選択後にユーザーのハッシュコードを保存し、と呼ばれるメソッドを使用してそのハッシュコードが変更されたかどうかを確認することisUserDirty()です。を使用して、マッピング内からその条件を簡単にテストできます<if test="isUserDirty">。もちろん、これはあまり一般的なアプローチではなく、適切なhashCode()の実装に依存します。より一般的なアプローチについては、同様の質問に対するleonbloyの回答をご覧ください。もちろん、これはまだ少し単純すぎるかもしれません。特に、多対多の関係について話しているからです。どちらのアプローチが最適かは、ケースによって異なります。

今、あなたは何をすべきかを知っている必要があります。幸運を!

PSデルタを挿入して削除する代わりに、単純な上書きをお勧めします。トランザクションで、すべてを削除してからすべてを挿入します。一時テーブル戦略は、データベースのパフォーマンスを実際にはまったく改善しない可能性のある最適化戦略です。実際、おそらくそれが悪化するのではないかと思います。この戦略を適切にプロファイリングし、何をしているのかを知っている場合は、この追記を無視してかまいません。

于 2013-05-09T16:42:13.143 に答える