工作中正好碰到这个问题,于是学习以下两个文章。先介绍了一些知识。后加入了对知识的分析,方便理解。并对可能的原理进行推测,以后有空看源码。
文章一
文章二
做java的WEB开发,通常都是分层的,包括action(controller层),service层,dao层。这里重点说说service层,也就是业务逻辑层的事务问题。
1.首先说一说action(controller)层
这一层是与web应用密切相关的,主要是处理request与response。把请求中的东西拿出来,作为业务层的输入,再把业务层的结束包装(处理)后,产生响应对象。
代码要求:
功能分层来说,这个action层功能主要是处理web的数据的,通常是不应该含有事务逻辑的,如果有请另包装到到一个service中。我经常看到一些代码把request传递到service中处理,问过原因,说是参考其它人的代码也是这么写的。所以告诉原因很重要。业务通用性来讲,业务逻辑不一定都是给web用的,总不能让非web的应用,数据包装成request来用吧。
2.spring注解事务
我们现在都用注解方式,很多时候只是写一个@Transactional。实际上后面可以设置多种参数。
有表明传播性与隔离级别。比如:
@Transactional(propagation = Propagation.REQUIRES_NEW)。不写的情况下,默认是:PROPAGATION_REQUIRED。
也有表明引起事务回滚的异常类:
@Transaction(noRollbackFor=RuntimeException.class)
@Transaction(RollbackFor=Exception.class)
不写的情况下,默认是:RuntimeException,只回滚unchecked异常。
另外还有一个readOnly = true,最后会讲。
默认配置,能够满足正常的需要,没有特殊情况就只要一个@Transaction。但要注意后面提到的异常处理。
3.关于spring注解事务的异常
代码要求:按默认情况配置,也就是不配置。自定义业务中异常的时候,让自定义的异常继承自RuntimeException,这样抛出的时候才会被Spring默认的事务处理准确处理。如果是一个servive中产生了checked异常,请在本service方法中处理掉或者另抛出unchecked一场,否则如果有外层service,将不知道要不要回滚整个事务。
通常我们的项目中,注意异常的处理就可以了。
以下讨论的回滚都指unchecked异常,先是主要的几种传播与隔离配置。
3.PROPAGATION_REQUIRED
一般文章介绍:默认事务类型,如果没有,就新建一个事务;如果有,就加入当前事务。适合绝大多数情况。
结论:
内外都无trycatch情况:
这样在方法中任何地方发生unchecked异常将触发整个方法的回滚。
无论内外层产生unchecked异常,都回滚。
如果有trycatch情况:
外层发生了unchecked异常,但被外层trycatch了,那是不会回滚的。
内层发生了unchecked异常,但外层有trycatch,但还是回滚了。按说外层的AOP是感受不到抛出的异常的,怎么会回滚呢?我猜测是内层的AOP也抛出了一个不能被外层trycatch的异常,而被外层的AOP感受到了。
内层发生了unchecked异常,但内层有trycatch,内层不回滚,如果外层正常,也不回滚了。
4.PROPAGATION_NESTED
一些文章先测试再讲规则,有点不知其所以然的感觉,所以我先查查什么是嵌套事务及其原则?
嵌套事务是一个外部事务的一个子事务,是一个外部事务的一个组成部分,当嵌套事务发生异常而回滚,则会恢复到嵌套事务的执行前的状态,相当于嵌套事务未执行。
如果外部事务回滚,则嵌套事务也会回滚!!!外部事务提交的时候,嵌套它才会被提交。
定义明确了,无论是交给spring处理NESTED事务,还是数据库处理NESTED事务,或者你设计什么事务时,原则都应该一样。
当所调用的方法为NESTED事务,该事务的回滚可以不影响到调用者的事务
当然如果子事务没有trycatch,异常冒泡而出,就将触发调用者事务的回滚。子事务有了trycatch就不会影响到外部调用者事务了,不会触发整个方法的回滚。
而调用者出现unchecked异常,却能触发所调用的nested事务的回滚!
5.PROPAGATION_REQUIRES_NEW
更少用到了此情况,通常可以将此部分代码放在事务之外执行 实在剥离不开才会用到。当被调用时,就相当于暂停(挂起)当前事务,先开一个新的事务去执行REQUIRES_NEW的方法,如果REQUIRES_NEW中的异常得到了处理那么他将不影响调用者的事务,同时,调用者之后出现了异常,同样也不会影响之前调用的REQUIRES_NEW方法的事务.
有个猜测:但是如果如果内部REQUIRES_NEW中的异常没有处理,异常冒泡会影响到调用者吧!
6.REQUIRES_NEW与NESTED比较
PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, REQUIRES_NEW 完全是一个新的事务,而NESTED 则是外部事务的子事务,如果外部事务commit,嵌套事务也会被commit, 这个规则同样适用于rollback。
PROPAGATION_NESTED可以在外层rollback所有内层的事务。REQUIRES_NEW不行。
后面再介绍几个配置参数,简单介绍就明白了。
7.PROPAGATION_SUPPORTS:如果没有,就以非事务方式执行;如果有,就使用当前事务。
8.PROPAGATION_NOT_SUPPORTED:如果没有,就以非事务方式执行;如果有,就将当前事务挂起。即无论如何不支持事务。
例子如下面的文章:
微信文章
上面的文章中,介绍了一个事务的业务中,突然要加一个非事务的方法。非事务的方法不能是本对象里的方法,不能是private方法,只能是public的,而且只有另写对象,以注入的方式,才能实现事务之间的关系处理。因为AOP代理了这些方法所在的业务对象。
9.PROPAGATION_NEVER:如果没有,就以非事务方式执行;如果有,就抛出异常。
10.PROPAGATION_MANDATORY:如果没有,就抛出异常;如果有,就使用当前事务。
11.引伸的配置@Transactional(readOnly = true)
从这一点设置的时间点开始(时间点a)到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!(查询中不会出现别人在时间点a之后提交的数据)。
应用场合:
如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;
如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。
【注意是一次执行多次查询来统计某些信息,这时为了保证数据整体的一致性,要用只读事务】
在将事务设置成只读后,相当于将数据库设置成只读数据库,此时若要进行写的操作,会出现错误。
项目中的使用情况:目前的项目几乎没有实时的,多条相关的只读查询,不需要这个设置。
注:以上的总结都没有时间亲测,只是看一些文章的总结。如有错误,欢迎指正。
-------------------------------------------------------------------------
另记录一个问题解决:之前部署的一个应用,平时正常,但经常早上不能访问,很是着急,上班前要花时间远程处理。发现是应用服务器与数据库服务器的网线直连不通了,时间紧就重启下。后来发现只要网络禁用再启动就行了。
后来几次后没找到原因,没条件换硬件或者不断修改配置来测试。突然想到定时任务,于是查到可以自动禁用启用网络的命令。至此,这个麻烦的问题再也没出现过了。
- 大小: 47.9 KB
分享到:
相关推荐
本文将深入探讨Spring中的几种事务配置方式,帮助开发者更好地理解和运用。 1. **编程式事务管理** 编程式事务管理是在代码中显式调用事务API来控制事务的开始、提交、回滚等操作。这种方式直接在业务逻辑代码中...
以下是关于Spring声明式事务配置管理的详细说明: 1. **事务管理器配置**: 在`/WEB-INF/applicationContext.xml`文件中,我们需要定义一个事务管理器Bean。通常,对于Hibernate,我们会使用`...
这种方法只需要在 Spring 配置文件中定义一个事务管理对象(如 DataSourceTransactionManager),然后加入 `<tx:annotation-driven/>` 节点,引用该事务管理对象,然后即可在需要进行事务处理的类和方法使用 `@...
Spring 事务配置是Spring框架中不可或缺的部分,它用于管理和协调应用程序中的事务边界,确保数据的一致性和完整性。...在使用过程中,还需注意事务的隔离级别、传播行为、回滚规则等事务特性,确保事务管理正确无误。
### Spring 事务传播属性详解 #### 一、Spring 事务基础概述 在深入探讨Spring框架中的事务传播属性...此外,需要注意的是,在实际开发中,还应结合事务的隔离级别、读写锁等其他高级特性来进一步优化事务管理策略。
本文将详细介绍Spring中的三种事务配置方式:编程式事务管理、声明式事务管理以及基于注解的事务管理。 **1. 编程式事务管理** 编程式事务管理是通过编程的方式手动控制事务的开始、提交、回滚等操作。主要使用`...
5. **事务配置**:在Spring XML配置文件中,我们需要配置事务管理器,例如DataSourceTransactionManager用于JDBC事务,HibernateTransactionManager用于Hibernate事务。同时,还需要开启事务代理,如下所示: ```...
4. **事务配置**:在Spring中,事务管理有两种方式:编程式事务管理和声明式事务管理。通常我们采用声明式事务管理,通过`<tx:annotation-driven>`标签启用基于注解的事务管理。事务的传播行为、隔离级别、超时时间...
3. **@Transactional注解**:在Java代码中,我们可以在Service层或者DAO层的方法上使用`@Transactional`注解,指定事务的属性,如传播行为、隔离级别、超时时间等。例如: ```java @Service public class ...
在提供的压缩包文件`Spring-JDBC`中,可能包含Spring与JDBC集成的相关示例,比如数据库连接池配置、JdbcTemplate的使用等,这些都是在Spring环境中进行事务管理的基础。通过理解并实践这些配置,你可以更好地掌握...
以下是关于Spring声明式事务配置方法的详细解释。 首先,Spring声明式事务管理主要依赖于AOP(面向切面编程)实现。通过在配置文件中定义事务的规则,Spring可以在特定的方法执行前后自动地进行事务的开启、提交、...
在需要进行事务处理的业务层方法上添加@Transactional注解,指定事务属性如传播行为、隔离级别、读写模式等。例如: ```java @Service public class UserService { @Transactional public void addUser(User ...
Spring框架在处理事务时提供了五种不同的配置方式,这些配置主要涉及到事务的声明式管理和编程式管理。在Spring中,事务管理通常分为三部分:...在实际应用中,应根据项目需求和性能考虑选择合适的事务配置方式。
这个标签告诉Spring容器自动检测带有@Transactional注解的类,并根据注解中的属性进行事务配置。 接下来,我们需要配置数据源和事务管理器。数据源(DataSource)是连接到数据库的资源,Spring提供了多种数据源实现...
本资源主要介绍基于Spring JDBC的事务管理,包括事务的定义、使用 @Transactional 注解、Spring JDBC的事务管理机制、事务的ACID特性、事务的传播、事务的隔离等内容。 事务的定义 事务是一种数据库中能够保证一...
2. **定义事务策略**:我们需要在TransactionProxyFactoryBean的配置中指定事务管理器(如DataSourceTransactionManager或JtaTransactionManager),并设置相应的事务属性,如隔离级别、传播行为、回滚规则等。...
`@Transactional`是Spring提供的一个注解,可以标记在类或方法级别,用于声明事务的属性,如传播行为、隔离级别、读写模式等。例如: ```java @Service public class UserService { @Transactional public void ...
在Spring框架中,声明式事务管理是通过AOP(面向切面编程)实现的,它允许开发者无需在业务代码中显式处理事务,而是通过配置来控制事务的边界。Spring提供了四种不同的方式来配置声明式事务,这使得事务管理更加...