用mybatis保存/更新集合,常见的做法是什么?



我决定尝试在一个新项目中使用mybatis。我对SQL相当熟悉,最近我在hibernate上有一些不好的经历,所以我正在寻找一种更低级的DAO方法。

看起来非常好,除了一件事,那就是处理集合。

我有两个pojo,组和用户,它们是多对多的。我已经决定了一个设计理念,即具有集合的POJO应该只在保存时更新表之间的M-M关系。因此,例如,当我保存一个具有用户集合的组对象时,设计原则规定应该已经保存了用户,并且我只需要在数据库中保存组和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>

按预期工作(插入/更新组,将用户集合保存为数据库中的关系)。但我不觉得这是最好的做法。创建这个应用程序是为了在需要时切换到hibernate,因此保存集合的逻辑最好位于数据库层。在我的atis中是否有一些我不知道的"魔法"可以简化这样的操作?

对于如何改进这一点有什么想法吗?或者我应该重新考虑应用程序的设计,并将集合的处理放在模型的更上层?

saveGroup数据映射操作的第二部分确实是重新考虑应用程序设计的原因。为了插入和删除增量,将内存中的用户集合持久化到临时表中,并将其与持久化表进行比较,这是一项相当繁重的操作,如果只是需要更新组的名称或描述,则根本没有必要,即当没有增量时。这种情况是否存在可以由数据库服务器(即您当前的解决方案)或数据库客户端(即您的应用程序)决定。

除了组及其可能的用户需要第一次插入的情况外,如果您希望应用程序决定是否需要更新链接表,那么您的应用程序需要知道用户集合自从数据库检索以来是否发生了更改。不幸的是,MyBatis不会帮助您的应用程序做到这一点。

看,与Hibernate相比,MyBatis完全不知道你的对象和它们在MyBatis完成它的工作后所携带的状态,这是数据映射,而不是对象关系映射。Hibernate可以自动检测对象的所谓脏状态,而MyBatis不能,因为这从来都不是它的工作描述的一部分。所以你只能自行其是了

一种超级简单的方法是在选择之后存储用户的哈希码,并使用称为isUserDirty()的方法检查该哈希码是否已更改。您可以简单地在映射中使用<if test="isUserDirty">测试该条件。当然,这不是一种非常通用的方法,它依赖于良好的hashCode()实现。看看leonbloy对类似问题的回答,了解更一般的方法。当然,这可能还是有点太简单了,特别是因为我们讨论的是多对多关系。哪种方法是最好的完全取决于你的情况。

现在你应该知道该怎么做了。好运!在一个事务中,我建议使用一个简单的覆盖,而不是插入和删除增量:删除所有,然后插入所有。您的临时表策略是一种优化策略,实际上可能根本不会提高数据库的性能,实际上我的猜测是它可能会使性能变得更糟。如果你正确地描述了这个策略,并且知道你在做什么,你可以忽略这个附注。

最新更新