Chú thích @Transactional. Làm thế nào để khôi phục?


91

Tôi đã sử dụng thành công chú thích này cho một lớp người Dao. Và khôi phục hoạt động cho các thử nghiệm.

Nhưng bây giờ tôi cần khôi phục mã thực chứ không chỉ kiểm tra. Có các chú thích đặc biệt để sử dụng trong các bài kiểm tra. Nhưng chú thích nào dành cho mã không thử nghiệm? Đó là một câu hỏi lớn đối với tôi. Tôi đã dành một ngày cho điều đó rồi. Tài liệu chính thức không đáp ứng nhu cầu của tôi.

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();
    }
}

nhân viênDao là

@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);
    }
}

Và đây là bài kiểm tra xem các chú thích hoạt động tốt:

@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>
   ...



** CÓ, tôi đã lùi giao dịch. Tôi vừa thêm BEAN cho dịch vụ ... và sau đó chú thích @Transactional bắt đầu hoạt động :-) **

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

Cảm ơn tất cả, Nga sẽ không quên bạn!

Câu trả lời:


163

Chỉ cần ném bất kỳ RuntimeExceptiontừ một phương thức được đánh dấu là @Transactional.

Theo mặc định, tất cả RuntimeExceptiongiao dịch khôi phục của s trong khi các ngoại lệ đã kiểm tra thì không. Đây là một di sản của EJB. Bạn có thể định cấu hình điều này bằng cách sử dụng rollbackFor()noRollbackFor()tham số chú thích:

@Transactional(rollbackFor=Exception.class)

Điều này sẽ khôi phục giao dịch sau khi ném bất kỳ ngoại lệ nào .


1
Tôi đã thử nó. Nó không hoạt động! Tôi nói về hoạt động Rollback không trực tiếp trong đối tượng Dao, điều đó có thể sẽ hoạt động. Tôi kể về một đối tượng khác sử dụng chuỗi lệnh gọi của Dao methoda sử dụng @Transactional. Và tôi cố gắng thêm chú thích tương tự cho lớp của tôi gọi là Đạo này. Nhưng nó không hoạt động ở đây.
Moscow Boy

5
Nó thực sự hoạt động theo cách này :-). Nếu bạn có một dịch vụ gọi một số DAO, dịch vụ đó cũng cần phải có @Transactionalchú thích. Nếu không, mỗi cuộc gọi DAO bắt đầu và cam kết giao dịch mới trước khi bạn đưa ra một ngoại lệ trong dịch vụ. Điểm mấu chốt là: ngoại lệ phải để lại (thoát) một phương thức được đánh dấu là @Transactional.
Tomasz Nurkiewicz,

Nhìn vào mã đã thêm trong bài viết đầu tiên. Tôi có một phần mã. Và sau khi thực hiện, tôi có bản ghi trong DB. => rollback vẫn chưa hoạt động.
Moscow Boy

Việc ném một ngoại lệ từ DAO cũng không quay trở lại giao dịch? Bạn đã org.springframework.orm.hibernate3.HibernateTransactionManagerđịnh cấu hình trong bối cảnh Mùa xuân của mình chưa? Nếu bạn bật trình org.springframework.transactionghi nhật ký, nó có hiển thị điều gì thú vị không?
Tomasz Nurkiewicz,

1
Nếu bạn đang sử dụng Spring Boot và để nó tự động định cấu hình DataSource, nó sẽ sử dụng HikariDataSource có cài đặt tự động cam kết thành true theo mặc định. Bạn cần đặt nó thành false: hikariDataSource.setAutoCommit (false); Tôi đã thực hiện thay đổi này trong lớp @Configuration khi định cấu hình bean DataSourceTransactionManager.
Alex

83

hoặc theo chương trình

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

12
Đúng. Bởi vì đôi khi bạn cần phải quay lại mà không gặp lỗi.
Erica Kane

2
Bạn là một cứu cánh.
Walls

Đây là một cách thích hợp hơn để gọi một imo khôi phục, lý tưởng là bạn không muốn ném các ngoại lệ cho các điều kiện đã biết hoặc được kiểm soát.
jalpino

2
Đôi khi nó không hoạt động. Ví dụ: trong trường hợp của tôi, tôi có một dịch vụ giao dịch và kho lưu trữ phi giao dịch. Tôi gọi kho lưu trữ từ dịch vụ, vì vậy, nó sẽ tham gia vào một giao dịch được mở bởi dịch vụ. Nhưng nếu tôi gọi mã của bạn từ kho lưu trữ không giao dịch của tôi, nó sẽ ném NoTransactionException mặc dù thực tế là giao dịch tồn tại.
Victor Dombrovsky

3
bạn muốn khôi phục giao dịch nào trong "kho lưu trữ không giao dịch" của mình?
Stefan K.

5

Bạn có thể ném một ngoại lệ không được chọn từ phương thức mà bạn muốn khôi phục. Điều này sẽ được phát hiện bởi mùa xuân và giao dịch của bạn sẽ được đánh dấu là chỉ khôi phục.

Tôi giả sử bạn đang sử dụng Spring ở đây. Và tôi cho rằng các chú thích mà bạn đề cập đến trong các bài kiểm tra của mình là các chú thích dựa trên bài kiểm tra mùa xuân.

Cách được khuyến nghị để chỉ ra cho cơ sở hạ tầng giao dịch của Spring Framework rằng công việc của giao dịch sẽ được khôi phục là đưa ra một Ngoại lệ từ mã hiện đang thực thi trong ngữ cảnh của một giao dịch.

và lưu ý rằng:

xin lưu ý rằng mã cơ sở hạ tầng giao dịch của Spring Framework, theo mặc định, sẽ chỉ đánh dấu một giao dịch để khôi phục trong trường hợp thời gian chạy, các ngoại lệ chưa được kiểm tra; nghĩa là, khi ngoại lệ được ném là một thể hiện hoặc lớp con của RuntimeException.


1

Đối với tôi rollbackFor là không đủ, vì vậy tôi phải đặt nó và nó hoạt động như mong đợi:

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

Tôi hy vọng nó sẽ giúp :-)


1
không có nó không giúp gì cả TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();bên dưới, bạn giúp
Enerccio
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.