我在我的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代码中。在没有并发DB更新的情况下,上面的设置将完全符合我的要求。不清楚的部分是并发DB更新会发生什么--即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语句的复杂存储过程,第二种方法更安全。
发布于 2011-07-05 21:19:36
首先,我必须说明显而易见的一点:您应该认真地避免在存储过程中执行自己的事务管理。
假设这是您唯一的选择,我会说后一种解决方案将是我的首选,因为任何开发人员都很清楚,id是从事务中返回的。
https://stackoverflow.com/questions/5388052
复制相似问题