Анотація @Transactional. Як відмовити?


91

Я успішно використав цю анотацію для класу Дао. І відкат працює для тестів.

Але зараз мені потрібно відмовити реальний код, а не лише тести. Існують спеціальні примітки для використання в тестах. Але які анотації призначені для нетестового коду? Для мене це велике питання. Я вже витратив на це день. Офіційна документація не відповідала моїм потребам.

class MyClass { // this does not make rollback! And record appears in DB.
        EmployeeDaoInterface employeeDao;

        public MyClass() {
            ApplicationContext context = new ClassPathXmlApplicationContext(
                    new String[] { "HibernateDaoBeans.xml" });
            employeeDao = (IEmployeeDao) context.getBean("employeeDao");
         }

        @Transactional(rollbackFor={Exception.class})
    public void doInsert( Employee newEmp ) throws Exception {
        employeeDao.insertEmployee(newEmp);
        throw new RuntimeException();
    }
}

працівник Дао є

@Transactional
public class EmployeeDao implements IEmployeeDao {
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void insertEmployee(Employee emp) {
        sessionFactory.getCurrentSession().save(emp);
    }
}

І ось тест, для якого анотації працюють добре:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/HibernateDaoBeans.xml" })
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
@Transactional
public class EmployeeDaoTest {

    @Autowired
    EmployeeDaoInterface empDao;

    @Test
    public void insert_record() {
       ...
       assertTrue(empDao.insertEmployee(newEmp));
    }

HibernateDaoBeans.xml

   ...
<bean id="employeeDao" class="Hibernate.EmployeeDao">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
    <tx:annotation-driven transaction-manager="txManager"/>

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
   ...



** ТАК, я відмінив транзакцію. Я щойно додав BEAN для послуги ... а потім анотація @Transactional починає працювати :-) **

<bean id="service" class="main.MyClass">
    <property name="employeeDao" ref="employeeDao" />
</bean>

Дякую усім, Росія вас не забуде!

Відповіді:


163

Просто викиньте будь-який RuntimeExceptionіз методу, позначеного як @Transactional.

За замовчуванням усі RuntimeExceptionтранзакції відкоту s, тоді як перевірені винятки - ні. Це спадщина EJB. Ви можете налаштувати це за допомогою параметрів rollbackFor()та noRollbackFor()анотацій:

@Transactional(rollbackFor=Exception.class)

Це призведе до відкоту транзакції після видалення будь-якого винятку.


1
Я спробував. Вона не працює! Я розповідаю про операцію відкату не безпосередньо в об'єкті Dao, що може бути, буде працювати. Я розповідаю про інший об'єкт, який використовує послідовність виклику методу Dao, який використовує @Transactional. І я намагаюся додати ту саму анотацію для свого класу, яка називає це Дао. Але тут це не працює.
Moscow Boy

5
Це справді працює таким чином :-). Якщо у вас є служба, яка викликає кілька DAO, служба також повинна мати @Transactionalанотацію. В іншому випадку кожен виклик DAO починається та робить нову транзакцію, перш ніж ви викинете виняток у службі. Суть: виняток повинен залишити (уникнути) метод, позначений як @Transactional.
Томаш Нуркевич,

Подивіться на доданий код у першому дописі. У мене є частина коду. І після виконання у мене є запис у БД. => відкат ще не працює.
Moscow Boy

Викидання винятку з DAO також не скасовує транзакцію? Ви org.springframework.orm.hibernate3.HibernateTransactionManagerналаштували у своєму контексті Spring? Якщо ви ввімкнете org.springframework.transactionреєстратор, він показує щось цікаве?
Томаш Нуркевич,

1
Якщо ви використовуєте Spring Boot і дозволяєте йому автоматично налаштовувати DataSource, він буде використовувати HikariDataSource, для якого за замовчуванням встановлено значення true-commit. Вам потрібно встановити значення false: hikariDataSource.setAutoCommit (false); Я вніс цю зміну в клас @Configuration під час налаштування компонента DataSourceTransactionManager.
Олексій

83

або програмно

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

12
Так. Тому що іноді потрібно відкат, не видаючи помилки.
Еріка Кейн,

2
Ви рятівник.
Стіни

Це більш підходящий спосіб викликати відкат imo, в ідеалі ви не хочете створювати винятки для відомих або контрольованих умов.
jalpino

2
Іноді це не працює. Наприклад, у моєму випадку я маю транзакційну службу та нетранзакційне сховище. Я викликаю сховище зі служби, тому він повинен брати участь у транзакції, відкритої сервісом. Але якщо я закликаю ваш код із мого нетранзакційного сховища, він видає NoTransactionException, незважаючи на той факт, що транзакція існує.
Віктор Домбровський

3
яку транзакцію ви хочете відкотити у своєму "нетранзакційному сховищі"?
Стефан К.

5

Ви можете викинути неперевірений виняток із методу, який ви хочете відкотити. Це буде виявлено навесні, а ваша транзакція буде позначена як лише відкат.

Я припускаю, що ви тут використовуєте Весну. І я припускаю, що анотації, на які ви посилаєтесь у своїх тестах, є анотаціями на основі весняного тесту.

Рекомендований спосіб інформування транзакційної інфраструктури Spring Framework про те, що роботу транзакції потрібно відмовити, - це викид винятку з коду, який виконується в даний час у контексті транзакції.

та зверніть увагу, що:

зауважте, що код інфраструктури транзакцій Spring Framework за замовчуванням позначатиме транзакцію для відкату лише у випадку виконання, невстановлені винятки; тобто коли викинутий виняток є екземпляром або підкласом RuntimeException.


1

Для мене відкату For було недостатньо, тому мені довелося поставити це, і воно працює як слід:

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

Сподіваюся, це допоможе :-)


1
ні, це зовсім не допомагає TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();нижче, ніж ви допомогли
Enerccio
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.