关于Spring事务控制方面的问题,就是不在service层做控制
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Spring事务控制方面的问题,就是不在service层做控制相关的知识,希望对你有一定的参考价值。
现在我在写一个小系统,需要引入事务控制相关的东西。
原来与spring事务都是在service层做的,现在我这个系统有需求是在controller层(action层)做事务控制,请问这个可能吗?还有有没有具体的实现方法和事例。
public interface ITransactionManager
/**
* 该方法中是需要进行事务控制的内容
* @return
* @throws Exception
*/
Object doInTransaction() throws Exception;
public class DataSourceTransactionUtil
public Object execute(final ITransactionManager transactionManager)
DataSourceTransactionManager dataSourceTransactionManager = getDataSourceTransactionManager();
TransactionTemplate transactionTemplate = new TransactionTemplate(dataSourceTransactionManager);
return transactionTemplate.execute(new TransactionCallback()
public Object doInTransaction(TransactionStatus transactionStatus)
Object savepoint = transactionStatus.createSavepoint();
Object result = null;
try
result = transactionManager.doInTransaction();
catch(Exception e)
transactionStatus.rollbackToSavepoint(savepoint);
e.printStackTrace();
finally
transactionStatus.releaseSavepoint(savepoint);
return result;
);
private DataSourceTransactionManager getDataSourceTransactionManager()
return (DataSourceTransactionManager)getBean("transactionManager");
解释一下:
这段代码我记得是看了spring源码后自己写的。
1、getBean("transactionManager");是获得spring中事务管理器那个bean,你自己改名字。
2、把这段代码放到你的BaseAction中:
protected Object beginTransaction(ITransactionManager transactionManagerImpl)
DataSourceTransactionUtil dt = new DataSourceTransactionUtil();
return dt.execute(transactionManagerImpl);
3.在你需要开启事务的action中调用beginTransaction方法transactionManagerImpl这个对象你写个匿名内部类然后实现doInTransaction() 方法,在doInTransaction() 中去写你调用多个service的代码 参考技术A 调用的service层方法不要加事务,直接试试用@transaction到controller层方法呢。
controller层一个业务方法调用多个service层方法,是完全正常的,controller层仅仅做业务逻辑处理而不调用多个service层方法太少了。可以事务用于controller层,自己的理解:一个controller层的方法才是真正的业务方法,才是一个完整的业务块,数据就应该一致,所以事务就该加在该层(讨论交流,允许不一样的声音?) 参考技术B 做是肯定可以。但是不怎么好。
首先action应该只有具有请求services与基本逻辑控制,真正的业务处理与数据交互应该是放在service层。所以事物在这里再好不过了。建议考虑一下
如果要配置,把之前spring配置路径改成action的,然后在方法上加上Transactional注解就可以了吧。不知道你系统是不是这样。谢谢。追问
是的,我看到大部分都是放在service层的,不过我现在一个action方法里面一般都有几个service方法的调用 ,要这些全部成功了,成一次提交到数据库的,所以 我才想到在action层上做事务控制的,不知道这样会有什么后果
追答这个问题。所以说还是跟程序的结构有关。
如果你action没有多个service方法。而是将其在service层统一处理。现在也没这些事。
配置在action层没什么后果、只是你的结构对于MVC设计模式不是很规范而已。
就是说你现在配置在action层应该最好。
关于spring事务提交的传播行为
保持事务一致性
首先我们的spring配置文件的配置如上图,除了指定方法外其他都是受事务控制,在某个aop切面配置路径下,如果方法有异常 则进行回滚,并且还是方法内涉及到增删改的回滚;
关于事务的使用:
为了保证整体方法的事务一致性,方法内如果有多处对数据进行增删改,那么最好提取成一个service进行事务控制,如果全成功,则全部提交,否则全部回滚;
以下主要是在工作中遇到的实际问题:
Service层test()方法:
while(条件) // 满足条件,则对数据库增删改
由于公司限制,不允许贴代码
这里我在Service中进行一个wile循环,如果满足条件,我就对满足条件的这一条数据进行多次增删改;
这里有个问题,不论是否出现异常,我都catch处理了,导致了事务的大量堆积,因为while循环没跑完,test()方法没执行完,事务并不会进行提交,如果while循环中的数据量过大,很有可能造成锁库锁表的可能,会造成很多问题;
实际工作中的解决方案:
方案一:向上抽取,分割成多个独立事务
我们将test()方法中的while(条件)循环向上抽取,抽取至Controller层中,然后对满足while条件的每一条数据处理时放至一个service中,这样每次循环一次时,就整体对while中的处理提交一次事务,完美解决;
方案二:事务传播,嵌套事务,创建新的事务
带有注解@Transactional(propagation=Propagation.REQUIRES_NEW)的方法走完之后,数据就会被提交入库
while循环中如果对数据库的交互仅有一次,其他都为查询时,我建议使用这个注解,也就是说 service方法中嵌套另一个service方法,第二个service方法加上此注解,那么第二个servie方法就是新创建的事务,并进行独立提交入库;
另外需要注意方法内部调用@Transactional(propagation=Propagation.REQUIRES_NEW)注解不生效,比如A和B都在同一个方法中,A调用B,B方法是此注解,则不生效。同样,AOP拦截也拦截不到B
----REQUIRES_NEW传播说明----------------------------------------------------------------------------------------- @Service public class TestUserImpl implements TestUser @Transactional(propagation=Propagation.REQUIRED ) public void saveUserAll() //1、保存用户-- this.saveUser(); //2--情况一、记录日志的方法在本service-新事务 this.saveUserLog(); //2--情况二、记录日志的方法在另一个LogService-新事务 logService.saveUserLog(); int a=1/0;//异常 public void saveUser() User user = new User(); userDao.save(user); @Transactional(propagation= Propagation.REQUIRES_NEW) public void saveUserLog() UserLog log = new UserLog(); UserLogDao.save(log); ------------------------------saveUserAll在位置一,出异常,执行结果------------------------------------ 情况一、记录日志的方法在本service,saveUser回滚,saveUserLog回滚 情况二、记录日志的方法在另一个LogService-新事务,saveUser回滚,saveUserLog不回滚 总结:要想总的方法的异常不影响 新事务方法REQUIRES_NEW的提交,新事务的方法,要写在另一个service里
以上是个人工作中的一些见解和想法,如有错误,欢迎指正。
以上是关于关于Spring事务控制方面的问题,就是不在service层做控制的主要内容,如果未能解决你的问题,请参考以下文章