N распространенных ошибок при использовании @Transactional

Java

@TransactionalЭто аннотация, которую мы вряд ли сможем избежать при использовании Spring.Эта аннотация в основном используется для объявления транзакций. Его принцип реализации заключается в использовании Spring AOP для вплетения оператора реализации управления транзакциями до и после метода оформления аннотаций, поэтому разработчикам нужно использовать только одну аннотацию, чтобы заменить ряд утомительных задач кодирования, таких как запуск и закрытие транзакции.

Метод кодирования действительно прост, но поскольку интуитивно понятная логика реализации скрыта, некоторые неправильные методы кодирования могут привести к@TransactionalАннотация недействительна и не может достичь эффекта транзакции. Самое прямое проявление — выбрасывается исключение при выполнении метода, но транзакция не откатывается, что в итоге приводит к генерации грязных данных.

Я также написал интересное обсуждение в своем блоге доПозвольте задать вопрос: будет ли откатываться эта транзакция?, многие люди далистандартный неправильный ответ, Если вы этого не видели, почему бы вам не пойти и не бросить вызов?

Хотя некоторые особые ситуации обсуждались ранее, все еще есть небольшие партнеры, которые будут задавать некоторые вопросы о сбоях транзакций в электронных письмах и группах WeChat. В основном все еще@TransactionalСпособов объявить транзакцию недействительной действительно много! Итак, сегодня я напишу статью, чтобы обобщить ее.Если я столкнусь с этим снова в следующий раз, я открою эту статью и просматриваю одну за другой, чтобы увидеть, есть ли ошибка. Конечно, здесь могут быть упущения, поэтому, если у вас есть другие случаи ошибок, дайте мне знать, и я продолжу систематизировать их в этой статье.

1. Звоните в тот же класс

Случай ошибки:

public class A {
    
    public void methodA() {
        methodB();
        
        // 其他操作
    }

    @Transactional
    public void methodB() {
        // 写数据库操作
    }
    
}

Этот тип ошибки применяется ко всем аннотациям, реализованным на основе Spring AOP, например:«Использование @Async для реализации асинхронных вызовов»упоминается в@Asyncаннотация,«Использование @Scheduled для реализации запланированных задач»упоминается в@Scheduledзаметки иИспользование аннотаций кэша Springупоминается в@CacheableЗаметки и т. д.

Способ решения этой проблемы относительно прост, лучше разумно спланировать иерархические отношения, например так:

@Service
@AllArgsConstructor
public class A {
    
    private B b;
    
    public void methodA() {
        b.methodB();
        // 其他操作
    }
}

@Service
public class B {

    @Transactional
    public void methodB() {
        // 写数据库操作
    }
    
}

Уведомление: Здесь класс A использует конструктор для внедрения реализации B (почему это бесполезно?@Autowrire, вы можете взглянуть на это, опубликованное несколько дней назадКогда не следует вводить @Autowired), конструктор использует Lombok@AllArgsConstructorСгенерировать (если вы с этим не знакомы, можете прочитать предыдущую статьюЛомбок: сделать код JAVA более элегантным).

2. Модифицированный метод @Transactional не является общедоступным

Случай ошибки:

public class TransactionalMistake {
    
    @Transactional
    private void method() {
        // 写数据库操作
    }
    
}

Это также требование для аннотаций, реализованных на основе Spring AOP. Это самое простое, легкое для понимания и интуитивно понятное, поэтому я не буду его подробно описывать. Измените тип доступа к методу непосредственно наpublicВот и все.

3. Различные источники данных

Случай ошибки:

public class TransactionalMistake {

    @Transactional
    public void createOrder(Order order) {
        orderRepo1.save(order);
        orderRepo2.save(order);
    }

}

Иногда мы можем писать несколько источников данных одновременно в одной операции, например, в приведенном выше примере.orderRepo1а такжеorderRepo2связаны два разных источника данных. По умолчанию такие транзакции между источниками данных не будут успешными.

Если вы хотите реализовать транзакции между несколькими источниками данных, вы можете ввести JTA, Если вы хотите это сделать, вы можете увидеть предыдущий обмен.«Использование JTA для управления транзакциями нескольких источников данных»

4. Неправильная конфигурация исключений отката

По умолчанию толькоRuntimeExceptionа такжеErrorСделайте откат. Если они и их потомки не являются исключениями, они не будут откатываться.

Поэтому при настройке исключений следует выполнить соответствующее планирование.Если вы хотите повлиять на откат транзакций, вы можете определить его какRuntimeExceptionподкласс ; если нетRuntimeException, но также хотите вызвать откат, то вы можете использоватьrollbackForсвойство, чтобы указать исключение для отката.

public class TransactionalMistake {

    @Transactional(rollbackFor = XXXException.class)
    public void method() throws XXXException {

    }

}

5. Механизм базы данных не поддерживает транзакции

Это пример из отзывов читателей.Код точно такой же как и у меня.Моя сторона хороша,но он просто не откатывается.

Позже выяснилось, что пропущена конфигурация ключевого атрибута:

spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

здесьspring.jpa.database-platformКонфигурация в основном используется для установки диалекта, используемого спящим режимом. Здесь специально используется MySQL5InnoDBDialect, в основном для того, чтобы при использовании Spring Data JPA Hibernate использовал механизм хранения InnoDB при автоматическом создании таблиц, иначе для построения таблиц будет использоваться механизм хранения по умолчанию MyISAM, а механизм хранения MyISAM не имеет транзакций.

Если ваша транзакция не вступила в силу, вы можете посмотреть в созданной таблице, используется ли механизм хранения MyISAM, если да, то причина в этом!

резюме

Если вы видите конец и обнаружите, что есть другие ситуации, которые не были рассмотрены, сообщите нам об этом, и мы продолжим обновлять эту статью! В помощь читателям, столкнувшимся с такими проблемами.

Что ж, сегодняшнее обучение здесь! Если вы столкнулись с трудностями в процессе обучения? может присоединиться к нашему супер высокому качествуГруппа весеннего технического обмена, участвовать в обменах и обсуждениях, лучше учиться и прогрессировать!

Приглашаю обратить внимание на мой публичный номер: Программист ДД, поделитесь галантереей и мыслями, которых не видно снаружи!