Настройка и использование транзакций Spring

Java

Транзакции, поддерживаемые Spring

Spring предоставляет два метода управления транзакциями: программный и декларативный.

  • 编程式: Включение, фиксация или откат транзакций вручную с помощью кодирования с более тонкой детализацией, но с большими проблемами.
  • 声明式: Обтекание путем добавления аннотаций к методам или классам или интерфейсам для реализации транзакций без навязчивости, что более удобно, но с большей степенью детализации.

Важно отметить, что используемая база данных должна поддерживать транзакции, иначе транзакции не будут работать. Например, механизм MyIsam MySql не поддерживает транзакции.

Конфигурация транзакций Spring

добавить зависимости

	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-tx</artifactId>
		<version>${spring.version}</version>
	</dependency>

Настройка диспетчера транзакций

	<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<!-- 如果使用基于注解的声明式事务,需要配置annotation-driven -->
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

Очевидно, что dataSource у transactionManager должен быть dataSource операции транзакции в коде, иначе как им управлять.

Использование алгоритмических транзакций

Запустите, зафиксируйте или откатите транзакцию в коде:

	// 开始事务
	TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
	// 异常回滚,并不一定要在try...catch中
	transactionManager.rollback(status);
	// 提交事务
	transactionManager.commit(status);

Как правило, подходящий метод использования:

	TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
	try {
		// 进行需要处在同一事务中的数据库操作
		......
		// 正常结束,提交事务
		transactionManager.commit(status);
	} catch (SomeException) {
		// 错误处理
		......
		// 回滚
		transactionManager.rollback(status);
	}

Использование декларативных транзакций

Добавить непосредственно в класс или в метод@TransactionПросто аннотируйте:

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
public int save(Info info) throws Exception {

@TransactionОбщие параметры аннотаций:

поведение распространения

  • REQUIRED(默认值)Должен выполняться в контексте с транзакцией: если текущей (внешней) транзакции нет, создается новая транзакция, если есть существующая (внешняя) транзакция, она добавляется к текущей (внешней) транзакции. (Если вызываемый метод выдает исключение, и вызывающий метод, и транзакция вызываемого метода будут отброшены.) Это наиболее распространенный выбор.
  • SUPPORTSПоддерживается текущая (внешняя) транзакция, и если текущая (внешняя) транзакция отсутствует, она выполняется нетранзакционным образом.
  • MANDATORYЗаставляет использовать текущую (внешнюю) транзакцию или создает исключение, если текущей (внешней) транзакции нет.
  • REQUIRES_NEWСоздайте новую транзакцию и запустите ее в транзакции. Если есть текущая (внешняя) транзакция, сначала приостановите текущую (внешнюю) транзакцию.
  • NOT_SUPPORTEDВыполнить операцию без транзакций: приостановить текущую (внешнюю) транзакцию, если есть текущая (внешняя) транзакция.
  • NEVERВыполнить нетранзакционно: выдает исключение, если в данный момент существует (внешняя) транзакция.
  • NESTEDВыполнение вложенным образом: если есть текущая (внешняя) транзакция, она будет выполняться независимо в своей собственной транзакции вложенным образом, не затрагивая текущую (внешнюю) транзакцию, и если текущая (внешняя) транзакция откатывается, Транзакция также должна быть отброшена, если (внешняя) транзакция в настоящее время не существует, выполняется операция, аналогичная PROPAGATION.REQUIRED.

уровень изоляции

  • DEFAULTИспользовать уровень изоляции транзакций базы данных по умолчанию
  • READ_UNCOMMITTEDРазрешает чтение незафиксированных изменений, что может привести к грязному чтению, фантомному чтению и неповторяемому чтению.
  • READ_COMMITTEDРазрешает чтение из зафиксированных транзакций, чтобы предотвратить грязное чтение, но фантомное чтение и неповторяемое чтение по-прежнему возможно.
  • REPEATABLE_READРезультаты многократного чтения одного и того же поля непротиворечивы, если данные не изменены самой текущей транзакцией. Грязные чтения и неповторяющиеся чтения можно предотвратить, но фантомные чтения все еще могут возникать.
  • SERIALIZABLEПолностью соблюдайте принцип изоляции ACID, чтобы гарантировать, что грязные чтения, неповторяемые чтения и фантомные чтения не происходят, но эффективность выполнения будет самой низкой.

readOnly — транзакция только для чтения

Указывает, читает ли транзакция только данные, но не обновляет данные. Установка для транзакции только для чтения значения только для чтения может помочь ядру базы данных оптимизировать транзакцию.

тайм-аут тайм-аут

Избегайте блокировки базы данных на долгое время, в секундах.

rollbackДля класса исключений отката

По умолчанию откатываются только исключения времени выполнения, см. ниже.

Подводные камни декларативных транзакций

внутренний вызов класса

Декларативная транзакция Spring динамически проксируется через АОП, поэтому будет создан класс, реализующий прокси транзакции, который отличается от исходного класса. Рассмотрим ситуацию:

  • Метод A в классе обслуживания не объявляет транзакцию
  • Метод B в службе объявляет транзакцию
  • Метод A вызывает метод B внутри

В это время вызывается метод B службы, и используется метод B прокси-класса Service', который реализует метод транзакции и будет откатываться при возникновении исключения.

Однако если вызывается метод A, а внутри прокси-класса используется метод B исходного класса Service, а транзакция не реализована, это вызовет аварийный откат.

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

Неправильное использование

Декларативный метод с оболочкой транзакции будет выполнять откат, когда метод выдает исключение, но по умолчанию он выдает только исключение.RuntimeExceptionоткат.

Если исключение проглочено уловом или не-RuntimeException, то по умолчанию откат не выполняется.

Решение: не проглатывать исключения, сталкиваться с не-RuntimeException,использовать@TransactionаннотированныйrollbackForпараметры контролируются.

Частичная иерархия классов java.lang в Java8 выглядит следующим образом (полную структуру см. в ссылках внизу статьи):

java.lang.Object
	......
	java.lang.Throwable (implements java.io.Serializable)
		java.lang.Error
			java.lang.AssertionError
			java.lang.LinkageError
				java.lang.BootstrapMethodError
				java.lang.ClassCircularityError
				java.lang.ClassFormatError
					java.lang.UnsupportedClassVersionError
				java.lang.ExceptionInInitializerError
				java.lang.IncompatibleClassChangeError
					java.lang.AbstractMethodError
					java.lang.IllegalAccessError
					java.lang.InstantiationError
					java.lang.NoSuchFieldError
					java.lang.NoSuchMethodError
				java.lang.NoClassDefFoundError
				java.lang.UnsatisfiedLinkError
				java.lang.VerifyError
			java.lang.ThreadDeath
			java.lang.VirtualMachineError
				java.lang.InternalError
				java.lang.OutOfMemoryError
				java.lang.StackOverflowError
				java.lang.UnknownError
		java.lang.Exception
			java.lang.CloneNotSupportedException
			java.lang.InterruptedException
			java.lang.ReflectiveOperationException
				java.lang.ClassNotFoundException
				java.lang.IllegalAccessException
				java.lang.InstantiationException
				java.lang.NoSuchFieldException
				java.lang.NoSuchMethodException
			// 这里是RuntimeException
			java.lang.RuntimeException
				java.lang.ArithmeticException
				java.lang.ArrayStoreException
				java.lang.ClassCastException
				java.lang.EnumConstantNotPresentException
				java.lang.IllegalArgumentException
					java.lang.IllegalThreadStateException
					java.lang.NumberFormatException
				java.lang.IllegalMonitorStateException
				java.lang.IllegalStateException
				java.lang.IndexOutOfBoundsException
					java.lang.ArrayIndexOutOfBoundsException
					java.lang.StringIndexOutOfBoundsException
				java.lang.NegativeArraySizeException
				java.lang.NullPointerException
				java.lang.SecurityException
				java.lang.TypeNotPresentException
				java.lang.UnsupportedOperationException
	......

использованная литература

Декларативные транзакции Spring — краткая книга

Spring Declarative Transaction Ошибка транзакции вызова метода в том же классе

java.lang Class Hierarchy (Java Platform SE 8 )

Переход от бумагимой блог, добро пожаловать в гости!