アノテーション@Transactional。ロールバックする方法は?


91

このアノテーションをDaoクラスにうまく使用しました。そして、ロールバックはテストで機能します。

しかし今は、テストだけでなく実際のコードをロールバックする必要があります。テストで使用する特別な注釈があります。しかし、どの注釈が非テストコード用ですか?それは私にとって大きな問題です。私はすでにそのために一日過ごしました。公式ドキュメントは私のニーズを満たしていませんでした。

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>

ありがとう、ロシアはあなたを忘れないでしょう!

回答:


160

RuntimeExceptionとしてマークされたメソッドから任意のものをスローするだけ@Transactionalです。

デフォルトでは、すべてRuntimeExceptionのsロールバックトランザクションがチェックされた例外では行われません。これはEJBのレガシーです。これはrollbackFor()noRollbackFor()アノテーションパラメータを使用して構成できます。

@Transactional(rollbackFor=Exception.class)

これにより例外がスローされた後にトランザクションがロールバックされます。


1
私はそれを試してみました。それは動作しません!Daoオブジェクトで直接ロールバック操作を行わないことについて説明します。@Transactionalを使用するDaoメソッドの呼び出しシーケンスを使用する別のオブジェクトについて説明します。そして、このDaoを呼び出す同じアノテーションをクラスに追加しようとします。ただし、ここでは機能しません。
モスクワ少年、

5
それは本当にこのように動作します:-)。複数のDAOを呼び出すサービスがある場合は、サービスに@Transactionalも注釈が必要です。それ以外の場合、サービスで例外をスローする前に、各DAO呼び出しが開始され、新しいトランザクションがコミットされます。要するに、例外はとマークされたメソッドを残す(エスケープする)必要があり@Transactionalます。
Tomasz Nurkiewicz

最初の投稿で追加されたコードを見てください。私が持っているコードの一部があります。そして実行後、DBにレコードができました。=>ロールバックはまだ機能しません。
モスクワ少年、

DAOから例外をスローしても、トランザクションはロールバックされませんか?あなたが持っているorg.springframework.orm.hibernate3.HibernateTransactionManagerあなたの春のコンテキストで構成されましたか?org.springframework.transactionロガーを有効にした場合、興味深いものは表示されますか?
Tomasz Nurkiewicz

1
Spring Bootを使用していて、DataSourceを自動構成させる場合は、デフォルトで自動コミットがtrueに設定されているHikariDataSourceを使用します。これをfalseに設定する必要があります:hikariDataSource.setAutoCommit(false); DataSourceTransactionManager Beanを構成するときに@Configurationクラスでこの変更を行いました。
アレックス

82

またはプログラム的に

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

12
はい。エラーをスローせずにロールバックする必要がある場合があるためです。
エリカケイン

2
あなたは命の恩人です。

これは、ロールバックimoを呼び出すより適切な方法です。理想的には、既知の条件または制御された条件で例外をスローしたくない場合です。
jalpino 2018

2
時々それは動作しません。たとえば、私の場合、トランザクションサービスと非トランザクションリポジトリがあります。サービスからリポジトリを呼び出すので、サービスによって開かれたトランザクションに参加する必要があります。しかし、非トランザクションリポジトリからコードを呼び出すと、トランザクションが存在するにもかかわらず、NoTransactionExceptionがスローされます。
Victor Dombrovsky

3
どのトランザクションを「非トランザクションリポジトリ」にロールバックしますか?
Stefan K.

5

ロールバックしたいメソッドから未チェックの例外をスローできます。これは春に検出され、トランザクションはロールバックのみとしてマークされます。

ここではSpringを使用していると思います。また、テストで参照する注釈は、スプリングテストベースの注釈であると想定しています。

Spring Frameworkのトランザクションインフラストラクチャに、トランザクションの作業がロールバックされることを示す推奨される方法は、現在トランザクションのコンテキストで実行されているコードから例外をスローすることです。

そして注意してください:

Spring Frameworkのトランザクションインフラストラクチャコードは、デフォルトでは、ランタイムのチェックされていない例外の場合にのみ、トランザクションにロールバックのマークを付けます。つまり、スローされた例外がRuntimeExceptionのインスタンスまたはサブクラスである場合。


1

私にとってはrollbackForでは不十分だったので、これを配置する必要があり、期待どおりに機能します:

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

それが役に立てば幸いです:-)


1
いいえ、それはすべてで助けていないTransactionAspectSupport.currentTransactionStatus().setRollbackOnly();、あなたは以下の助け
Enerccio
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.