Spring 如果在应用程序中抛出异常,则不回滚事务

Spring not roll back transaction if exception throws in the application

我使用 spring 事务开发应用程序并在 table 中插入记录。

我在 DAO class 中明确抛出异常,但 spring 将记录插入 table 而不是回滚事务。

我创建了如下两个应用程序。在案例 1 中,即使抛出异常,记录也会插入到 table 中。但是在案例 2 中,没有插入任何记录并且 spring 成功回滚事务。你能解释一下这两个应用程序之间的区别吗?

案例 1:

Item.java

public class Item {

    int itemNo;
    String itemName;
    String itemType;
    String itemSize;
    public int getItemNo() {
        return itemNo;
    }
    public void setItemNo(int itemNo) {
        this.itemNo = itemNo;
    }
    public String getItemName() {
        return itemName;
    }
    public void setItemName(String itemName) {
        this.itemName = itemName;
    }
    public String getItemType() {
        return itemType;
    }
    public void setItemType(String itemType) {
        this.itemType = itemType;
    }
    public String getItemSize() {
        return itemSize;
    }
    public void setItemSize(String itemSize) {
        this.itemSize = itemSize;
    }
}

ItemDao

@Service
public class ItemDao {

    @Autowired
    JdbcTemplate jdbcTemplate ;


    void insert(Item item){

        jdbcTemplate.update("insert into item_test(itemno, itemtype,itemsize,itemname) values (?,?,?,?)", new Object[]{item.getItemNo(),item.getItemType(),item.getItemSize(),item.getItemName()});
        int a=2/0;
    }
}

ItemService.java

@Service
public class ItemService {
    @Autowired
    ItemDao itemDao;    


    @Transactional
    public void insert(Item item){
        try{
            itemDao.insert(item);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
}

Test.java

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        ApplicationContext ct = new ClassPathXmlApplicationContext("spring.xml");
        ItemService itemService = ct.getBean("itemService", ItemService.class);

        Item item = new Item();
        item.setItemNo(1234);
        item.setItemName("sofa");
        item.setItemSize("4");
        item.setItemType("furniture");
        itemService.insert(item);
    }

}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!-- Enable Annotation based Declarative Transaction Management -->
    <tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager" />
    <context:component-scan base-package="com.spring.springtransaction" />
    <!-- Creating TransactionManager Bean, since JDBC we are creating of type 
        DataSourceTransactionManager -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- MySQL DB DataSource -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="oracle.jdbc.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@locahost:1521:xe)))" />
        <property name="username" value="system" />
        <property name="password" value="system" />
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <bean id="itemService" class="com.spring.springtransaction.ItemService" />
</beans>

案例二:

ItemService.java

@Service
public class ItemService {
    @Autowired
    ItemDao itemDao;

    @Autowired
    ItemManger itemManger;

    @Transactional
    public void insert(Item item){
        try{
            itemManger.insert(item);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
}

ItemManger.java

@Service
public class ItemManger {

    @Autowired
    ItemDao itemDao;


    @Transactional
    public void insert(Item item){

        itemDao.insert(item);

    }
}

ItemDao.java

@Service
public class ItemDao {

    @Autowired
    JdbcTemplate jdbcTemplate ;


    void insert(Item item){

        jdbcTemplate.update("insert into item_test(itemno, itemtype,itemsize,itemname) values (?,?,?,?)", new Object[]{item.getItemNo(),item.getItemType(),item.getItemSize(),item.getItemName()});
        int a=2/0;
    }
}

将您 ItemDao 注释为 @Repository 而不是 @Service

您应该使用 spring Transactional 上下文而不是 main 执行单元测试,例如使用 TestNG:

@ContextConfiguration(classes = {ConfigurationClass.class})
@ActiveProfiles({"test"})
public class TestItemDAO extends AbstractTransactionalTestNGSpringContextTests {
    @Autowired
    private ItemDao dao;
    @Test
    public void testItemDao() {
        dao.insert(item);
    }
}

删除 try 块,您正在尝试处理异常,所以这就是 RollbackException 不切断事务流的原因。