iBatis selectKey и транзакции - PullRequest
2 голосов
/ 22 марта 2011

Я использую 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 второй подход более безопасен.

1 Ответ

0 голосов
/ 06 июля 2011

Во-первых, я должен констатировать очевидное: вам следует серьезно постараться избежать самостоятельного управления транзакциями внутри хранимой процедуры.

Предполагая, что это ваш единственный вариант, я бы сказал, что последнее решение будет моим предпочтением, так как любому разработчику ясно, что идентификатор возвращается из транзакции.

...