คำอธิบายประกอบ @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();
    }
}

staffDao คือ

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

ขอบคุณทุกคนรัสเซียจะไม่ลืมคุณ!

คำตอบ:


165

เพียงแค่โยนใด ๆจากวิธีการทำเครื่องหมายว่าเป็นRuntimeException@Transactional

ตามค่าเริ่มต้นRuntimeExceptionธุรกรรมย้อนกลับทั้งหมดในขณะที่ข้อยกเว้นที่ตรวจสอบไม่ได้ นี่คือมรดกของ EJB คุณสามารถกำหนดค่าได้โดยใช้rollbackFor()และnoRollbackFor()พารามิเตอร์คำอธิบายประกอบ:

@Transactional(rollbackFor=Exception.class)

การดำเนินการนี้จะย้อนกลับธุรกรรมหลังจากที่มีข้อยกเว้น


1
ฉันลองแล้ว มันไม่ทำงาน! ฉันบอกเกี่ยวกับการดำเนินการย้อนกลับไม่ได้อยู่ในวัตถุ Dao โดยตรงนั่นอาจจะใช้ได้ ฉันบอกเกี่ยวกับวัตถุอื่นที่ใช้ลำดับการเรียกของ Dao methoda ที่ใช้ @Transactional และฉันพยายามเพิ่มคำอธิบายประกอบเดียวกันสำหรับชั้นเรียนของฉันที่เรียกสิ่งนี้ว่า Dao แต่มันไม่ทำงานที่นี่
Moscow Boy

5
มันใช้งานได้จริง ๆ :-) หากคุณมีบริการที่โทรหา DAO หลาย ๆ บริการจำเป็นต้องมี@Transactionalคำอธิบายประกอบด้วย มิฉะนั้นการโทร DAO แต่ละครั้งจะเริ่มต้นและทำธุรกรรมใหม่ก่อนที่คุณจะมีข้อยกเว้นในบริการ บรรทัดล่างคือ: ข้อยกเว้นต้องออก (หลบหนี) @Transactionalวิธีการทำเครื่องหมายว่าเป็น
Tomasz Nurkiewicz

ดูรหัสที่เพิ่มในโพสต์แรก มีส่วนหนึ่งของรหัสที่ฉันมี และหลังจากดำเนินการฉันมีบันทึกใน DB => การย้อนกลับยังไม่ทำงาน
Moscow Boy

การโยนข้อยกเว้นจาก DAO จะไม่ย้อนกลับธุรกรรมด้วยหรือไม่? คุณได้org.springframework.orm.hibernate3.HibernateTransactionManagerกำหนดค่าในบริบท Spring ของคุณหรือไม่? หากคุณเปิดใช้งานorg.springframework.transactionคนตัดไม้มันแสดงอะไรที่น่าสนใจหรือไม่?
Tomasz Nurkiewicz

1
หากคุณใช้ Spring Boot และปล่อยให้กำหนดค่า DataSource โดยอัตโนมัติระบบจะใช้ HikariDataSource ซึ่งตั้งค่าการส่งอัตโนมัติเป็นจริงตามค่าเริ่มต้น คุณต้องตั้งค่าเป็นเท็จ: hikariDataSource.setAutoCommit (false); ฉันทำการเปลี่ยนแปลงนี้ในคลาส @Configuration เมื่อกำหนดค่า DataSourceTransactionManager bean
Alex

83

หรือโดยทางโปรแกรม

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

13
ใช่. เพราะบางครั้งคุณต้องย้อนกลับโดยไม่เกิดข้อผิดพลาด
Erica Kane

2
คุณเป็นผู้ช่วยชีวิต
กำแพง

นี่เป็นวิธีที่เหมาะสมกว่าในการเรียกใช้ imo แบบย้อนกลับโดยหลักการแล้วคุณไม่ต้องการทิ้งข้อยกเว้นสำหรับเงื่อนไขที่ทราบหรือมีการควบคุม
jalpino

2
บางครั้งก็ไม่ได้ผล ตัวอย่างเช่นในกรณีของฉันฉันมีบริการธุรกรรมและที่เก็บที่ไม่ใช่ธุรกรรม ฉันเรียกที่เก็บจากบริการดังนั้นควรมีส่วนร่วมในธุรกรรมที่เปิดโดยบริการ แต่ถ้าฉันเรียกรหัสของคุณจากที่เก็บที่ไม่ใช่ธุรกรรมของฉันมันจะพ่น NoTransactionException แม้ว่าจะมีธุรกรรมอยู่ก็ตาม
Victor Dombrovsky

3
ธุรกรรมใดที่คุณต้องการย้อนกลับใน "พื้นที่เก็บข้อมูลที่ไม่ใช่ธุรกรรม" ของคุณ
Stefan K.

5

คุณสามารถโยนข้อยกเว้นที่ไม่ได้ทำเครื่องหมายออกจากวิธีการที่คุณต้องการย้อนกลับได้ สิ่งนี้จะถูกตรวจพบโดย Spring และธุรกรรมของคุณจะถูกทำเครื่องหมายว่าเป็นการย้อนกลับเท่านั้น

ฉันสมมติว่าคุณกำลังใช้ Spring ที่นี่ และฉันถือว่าคำอธิบายประกอบที่คุณอ้างถึงในการทดสอบของคุณเป็นคำอธิบายประกอบตามการทดสอบฤดูใบไม้ผลิ

วิธีที่แนะนำในการระบุโครงสร้างพื้นฐานธุรกรรมของ Spring Framework ว่างานของธุรกรรมจะถูกย้อนกลับคือการโยนข้อยกเว้นจากโค้ดที่กำลังดำเนินการในบริบทของธุรกรรม

และโปรดทราบว่า:

โปรดทราบว่าโดยค่าเริ่มต้นรหัสโครงสร้างพื้นฐานธุรกรรมของ Spring Framework จะทำเครื่องหมายเฉพาะธุรกรรมสำหรับการย้อนกลับในกรณีของรันไทม์ข้อยกเว้นที่ไม่ได้ตรวจสอบ นั่นคือเมื่อข้อยกเว้นที่ถูกโยนเป็นอินสแตนซ์หรือคลาสย่อยของ RuntimeException


1

สำหรับฉันการย้อนกลับสำหรับไม่เพียงพอดังนั้นฉันจึงต้องใส่สิ่งนี้และใช้งานได้ตามที่คาดไว้:

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

ฉันหวังว่ามันจะช่วย :-)


1
ไม่มันไม่ช่วยอะไรเลยTransactionAspectSupport.currentTransactionStatus().setRollbackOnly();ด้านล่างที่คุณช่วย
Enerccio
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.