Я использую iBatis с MySQL 5 в своем приложении Java.
У меня есть класс постоянных сущностей
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;
То, чего я пытаюсь добиться, - это получение вновь вставленного идентификатора сущности обратно в мой Java-код.При работе без одновременных обновлений БД, приведенная выше настройка будет делать именно то, что я хочу.Непонятная часть состоит в том, что происходит с одновременными обновлениями БД, т.е. каковы точные сроки и контекст iBatis, выполняющего оператор selectKey
- я предполагаю, что он не будет выполнен в рамках той же транзакции, которая определена в хранимой процедуре, поэтому это возможновозвращенный идентификатор не будет идентификатором объекта, который я хочу.
Единственное возможное решение, о котором я могу подумать, - это избегать использования selectKey
:
<insert id="insert" parameterClass="MyEntity">
{CALL insert_entity(#property#, #id,mode=OUT#)}
</insert>
Возвращая последний вставленный идентификаториз хранимой процедуры:
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;
Есть ли лучшее решение для этой проблемы?
Отредактировано: Документация MySQL для LAST_INSERT_ID
Состояния:
Созданный идентификатор поддерживается на сервере для каждого подключения.Это означает, что значение, возвращаемое функцией данному клиенту, является первым значением AUTO_INCREMENT, сгенерированным для самого последнего оператора, влияющего на столбец AUTO_INCREMENT этим клиентом.На это значение не могут повлиять другие клиенты, даже если они генерируют собственные значения AUTO_INCREMENT.Такое поведение гарантирует, что каждый клиент может получить свой собственный идентификатор, не заботясь об активности других клиентов и не нуждаясь в блокировках или транзакциях.
Так что кажется, что оригинальное решение с selectKey
будетработать во всех случаях.Однако для сложных хранимых процедур с несколькими операторами INSERT
второй подход более безопасен.