iBatis selectKey和交易

时间:2011-03-22 07:31:29

标签: mysql transactions ibatis

我在我的Java应用程序中使用iBatis和MySQL 5.

我有一个持久的实体类

public class Entity {
    private int id;
    private Stirng property;
    // setters and getters are omitted        
}

按如下方式插入新实体:

<insert id="insert" parameterClass="MyEntity">
    <selectKey resultClass="int" type="post" keyProperty="id" >
        select LAST_INSERT_ID() as value
    </selectKey>
    {CALL insert_entity(#property#)}
</insert>

在存储过程中管理事务,如下所示:

CREATE DEFINER=`user`@`%` PROCEDURE `insert`(IN p_property VARCHAR(255))
BEGIN
    START TRANSACTION;
        INSERT INTO entities (property) VALUES (p_property);
        -- Do more stuff that requires transaction: update more tables etc.
    COMMIT; 
END;

我想要实现的是将新插入的实体ID添加回我的Java代码。在没有并发数据库更新的情况下,上面的设置将完全符合我的要求。不清楚的部分是并发数据库更新会发生什么 - 即iBatis执行selectKey语句的确切时间和上下文 - 我猜它不会在存储过程中定义的同一事务中执行,所以它可能返回的id不是我想要的实体的id。

我能想到的唯一可行解决方案是避免使用selectKey

<insert id="insert" parameterClass="MyEntity">
    {CALL insert_entity(#property#, #id,mode=OUT#)}
</insert>

从存储过程返回最后一个插入的id:

CREATE DEFINER=`user`@`%` PROCEDURE `insert`(
       IN p_property VARCHAR(255),
       OUT p_id INTEGER(11),
)
BEGIN
    START TRANSACTION;
        INSERT INTO entities (property) VALUES (p_property);
        SELECT LAST_INSERT_ID() INTO p_id;
        -- Do more stuff that requires transaction: update more tables etc.
    COMMIT; 
END;

这个问题有更好的解决方案吗?


编辑: LAST_INSERT_ID州的MySQL文档:

  

生成的ID基于每个连接在服务器中维护。这意味着函数返回给定客户端的值是为该客户端影响AUTO_INCREMENT列的最新语句生成的第一个AUTO_INCREMENT值。此值不受其他客户端的影响,即使它们生成自己的AUTO_INCREMENT值。此行为可确保每个客户端都可以检索自己的ID,而无需关心其他客户端的活动,也无需锁定或事务。

因此,selectKey的原始解决方案似乎适用于所有情况。但是,对于具有多个INSERT语句的复杂存储过程,第二种方法更安全。

1 个答案:

答案 0 :(得分:0)

首先,我必须说明一点:您应该认真避免在存储过程中进行自己的事务管理。

假设这是你唯一的选择,我会说后一个解决方案是我的偏好,因为任何开发人员都清楚这个id是从事务中返回的。