我们有一个Spring Transaction回滚问题,其中回滚似乎不起作用。
在我用@Transactional
注释的服务层方法中,我调用了三个不同的DAOImpl
类来插入3条记录。
中间插入从第4个表中获取以填充描述字段但是这个失败了。我希望第一个插入回滚,但似乎没有发生。
几点:
org.springframework.jdbc.datasource.DataSourceTransactionManager
中定义的MySQL datasource
和applicationContext.xml
。 Bean在Beans.xml
中创建,导入ApplicationContext.xml
@Transactional
图层DAO
注释
<tx:annotation-driven transaction-manager="transactionManager"/>
applicationContext.xml
更新:
代码段....
服务类 - 这与我的相似......我在使用和不使用@Autowired进行测试。在服务类中调用事务启用方法。
public class CustomerService { //@Autowired CustomerOrderDAO customerOrderDAOImpl; //@Autowired CustomerItemDAO customerItemDAOImpl; //@Autowired CustomerPromotionDAO customerPromotionDAOImpl; //@Autowired PromotionDAO promotionDAOImpl; //other variables public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder) { try { saveOrderDetails(customerOrder); ..... return customerOrder; } catch (Exception e) //TO-DO catch proper exception { //Send error response ....... return customerOrder; } } @Transactional public void saveOrderDetails(CustomerOrder customerOrder) throws Exception { customerOrderDAOImpl.create(customerOrder); .... while (promotionsIterator.hasNext()) { customerPromotion.setPromotionName(promotionDAOImpl.getName(customerOrder.getPromotionId)); customerPromotionDAOImpl.create(customerPromotion); } ...... while (customerItemIterator.hasNext()) { customerItemDAOImpl.create(customerItem); } } }
有什么想法吗? 感谢。
答案 0 :(得分:4)
@Transactional
的默认行为是在对象周围添加了事务行为(代码中为CustomerService
)。从reference docs(向下滚动):
在代理模式(默认设置)下,只拦截通过代理进入的外部方法调用。这意味着实际上,自调用目标对象中的一个方法调用目标对象的另一个方法,即使被调用的方法用@Transactional标记,也不会在运行时导致实际的事务。
在您的示例中,对handlingIncomingOrders()
的外部调用将通过代理并命中目标对象(CustomerService
的实例)。但是,对saveOrderDetails()
的后续调用是目标对象内部的常规方法调用,因此永远不会调用代理中的事务行为。但是,如果从另一个类调用saveOrderDetails()
,您会发现事务行为将按预期工作。
答案 1 :(得分:1)
您的案例中的解决方案是调用saveOrderDetails(customerOrder);
作为proxyBean.saveOrderDetails(customerOrder);
调用proxybean is the Object on which
handleIncomingOrders`的位置。
如果CustomerService
为singleton
(Defualt范围),则可以像将以下代码添加到Service类一样简单。 (将自引用添加为自动装配)
//@Autowired
CustomerService customerService; // As this is injected its a proxy
并在方法中将其用作
public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder) {
try {
customerService.saveOrderDetails(customerOrder);
.....
return customerOrder;
} catch (Exception e) //TO-DO catch proper exception
{
//Send error response
.......
return customerOrder;
}
}
如果其范围为Prototype
,则可能的简单解决方案之一如下。
public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder, CustomerService customerService) {
try {
customerService.saveOrderDetails(customerOrder);
.....
return customerOrder;
} catch (Exception e) //TO-DO catch proper exception
{
//Send error response
.......
return customerOrder;
}
}
您致电handleIncomingOrders
的地方使用以下代码中建议的更改。
bean.handleIncomingOrders(customerOrder); //Suppose this is old code
Change it to
bean.handleIncomingOrders(customerOrder, bean);// THough it appears as we are sending reference to `THIS` as parameter whcihc can be unnecessary, in case of `Proxy`while inside your method `this` and `Passed reference` will point to different Obejects.