Транзакции с помощью весенних аннотаций - только для чтения или нет? - PullRequest
1 голос
/ 24 ноября 2011

У меня в проекте есть код, похожий на этот

@Transactional(readOnly = true)
public void tt() {
    dd();
}

@Transactional()
public void dd() {
    gg();
}

@Transactional(readOnly = true)
public void gg() {

}

Функция dd используется как другими функциями транзакции только для чтения, так и не только для чтения.Предполагая, что транзакция должна расширяться от выполнения tt до gg - операции в dd будут транзакцией только для чтения или нет?

Ответы [ 3 ]

6 голосов
/ 25 ноября 2011

В данном конкретном примере ваш вопрос спорный.

Вызов dd() из tt() не пройдет границу прокси, поэтому уведомление о транзакции не будет применено к dd() (поскольку это вызов внутри того же экземпляра). То же самое с звонком на gg() с dd(). Следовательно, только вызов извне tt() будет фактически рекомендован для транзакции (в вашем случае с readOnly=true), и это будет транзакция, которая будет использоваться во всей цепочке вызовов.

В общем случае прочтите документацию, подсказанную @melihcelik - она ​​объясняет поведение.

3 голосов
/ 24 ноября 2011

Spring's AbstractPlatformTransactionManager имеет свойство с именем validateExistingTransaction, которое управляет этим поведением.Javadoc утверждает, что:

При участии в существующей транзакции (например, с PROPAGATION_REQUIRES или PROPAGATION_SUPPORTS, обнаружившей существующую транзакцию), характеристики этой внешней транзакции будут применяться даже к внутренней области транзакции.Валидация обнаружит несовместимый уровень изоляции и настройки только для чтения в определении внутренней транзакции и соответственно отклонит участие, выдав соответствующее исключение.

Поскольку распространение по умолчанию для Spring @Transactional, аннотация - REQUIRED и по умолчаниюСтратегия валидации неверна, я ожидаю, что Spring будет использовать существующую транзакцию, созданную из вызова метода tt в режиме только для чтения.

Если вы хотите иметь транзакцию только для чтения, вы должны аннотировать свой метод с помощью:

  @Transactional(propagation=Propagation.REQUIRES_NEW, readOnly=true)
3 голосов
/ 24 ноября 2011

используйте @Transactional(readoOnly = true), если вы выполняете выборку / выборку и не вносите никаких изменений, это означает, что блокировки не будут применены (что более эффективно).

Для обновлений / вставок / удалений / сохранений / слияний, которые я использую (когда требуется блокировка):

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
...