声明式事务基本配置步骤
- 编程式事务:由程序员编程事务控制代码;
- 声明式事务:事务控制代码已经由spring写好,程序员只需要声明出那些方法需要进行事务控制和如何进行事务控制。
- 注意:
①声明式事务需要用到
tx
命名空间,都是针对服务层实现类serviceImpl
下的方法;
②事务管理器基于通知advice
的,也就是AOP;
- 步骤(spring配置文件:applicationContext.xml):
①通知类在spring-jdbc.jar中(DataSource下的DataSourceTransactionManager)
<!--配置事务管理器,需要连接数据库,在spring整合mybatis的基础上-->
<bean id=”txManager” class=”org.srpingframework.jdbc.datasource.datasourceTrancationManager”>
<property name=”datasource” ref=”dataSource”/>
</bean>
②添加tx命名空间,在其中配置声明式事务(控制哪个方法)
<!--配置声明式事务-->
<tx:advice id=”txAdvice” transaction-manager=”txManager”>
<tx:attributes>
<!--具体到那些方法需要有事务控制-->
<tx:method name=”方法名”/>
<tx:method name=”ins*”/>
<tx:method name=”del*”/>
<tx:method name=”upd*”/>
<tx:method name=”*” read-only=”true”/>
<!--表示以ins*,del*,upd*,*(*是补充)开头的所有方法-->
</tx:attributes>
</tx:advice>
③将txAdvice添加到aop中(控制那个类中有切点)
<!--切点范围应该大一点,那个类有事务-->
<aop:pointcut expression=”execution(* xxx.xxx.xxx.impl.*.*(..))”id=“mypoint”></aop:pointcut>
<aop:advisor advice-ref=”txAdvice” pointcut-ref=”mypoint”>
声明式事务中属性解释
<tx:method/> 中的属性解释。
①
name=""
哪些方法需要有事务控制,支持*通配符;
取值 | 作用 |
---|---|
方法名(如:insUsers) | 那个方法需要事务管理 |
②
read-only=""
是否是只读事务。
值 | 作用 |
---|---|
true | 告诉数据库此事务为只读事务,不做任何操作。数据库优化,会对性能有一定提升,所以只要是查询的方法,建议使用此数据 |
false (默认值) | 事务需要提交的事务,建议新增,删除,修改 |
③
propagation=""
控制事务传播行为,当一个具有事务控制的方法被另一个有事务控制的方法调用后,需要如何管理事务(新建事务\在事务中执行\把事务挂起\报异常)。
值 | 作用 |
---|---|
REQUIRED(默认值) | 如果当前有事务,就在事务中执行 (调用方法有事务,被调用方法不重新创建事务,在当前事务中执行);如果当前没有事务,新建一个事务。 |
SUPPORTS | 如果当前有事务,就在事务中执行;如果当前没有事务,就在非事务状态下进行。 (注意:假如insert方法采用这个管理方式,直接调用insert方法时,该方法在非事务状态下执行) |
MANDATORY | 必须在事务内部执行,如果当前有事务,就在事务中执行;如果没有事务,报异常。 (使用时尽量不用通配符*)。 |
REQUIRES-NEW | 必须在事务中执行,如果当前没有事务,就新建一个事务;如果当前有事务,就将当前事务挂起,新建事务。 |
NOT-SUPPORTED | 必须在非事务状态下执行,如果当前没有事务,就正常进行;如果当前有事务,就将当前事务挂起,正常执行。 |
NEVER | 必须在非事务状态下执行,如果当前没有事务,就正常进行;如果当前有事务,报异常。 |
NESTED | 必须在事务状态下执行。如果没有事务,就新建事务;如果当前有事务,创建一个嵌套事务。 |
④
isolation=""
事务隔离级别。在多线程或并发访问下,如何保证访问到的数据是具有完整性的。
脏读 | 指的是一个事务(A)读取到另一个事务(B)中未提交的数据,另一个事务中数据可能进行了改变,A事务读取的数据就可能和数据库中数据是不一致的。此时认为数据是脏数据,读脏数据的过程叫做脏读。 | – |
---|---|---|
不可重复读 | 主要针对某行数据(或行中某列),主要针对的操作是修改操作,两次读取在同一个事务内;当事务A第一次读取事务后,事务B对事务A读取的数据进行修改,事务A中再次读取的数据和之前读取的数据不一致,过程不可重复读。 | 解决方法:锁定某行 |
幻读 | 主要针对的操作是新增或删除。两次事务的结果。事务A按照特定条件查询出结果,事务B新增了一条符合条件的数据,事务A中查询的数据和数据库中的数据是不一致的,事务A好像出现了幻觉,这种情况称为幻读 | 解决办法:锁定整个数据库表 |
取值 | 作用 |
---|---|
DEFAULT(默认值) | 由底层数据库自动判断应该使用什么隔离级别 |
READ_UNCOMMITTED | 可以读取未提交数据,可能出现脏读,不可重复读,幻读;但效率最高 |
READ_COMMITTED | 只能读取其他事务已提交数据,可以防止脏读,可能出现不可重复读和幻读 |
REPEATABLE_READ | 读取的数据会被添加锁,防止其他事务修改此数据,可以防止不可重复读和脏读;但可能出现幻读 |
SERIALIZABLE | 排队操作,对整个表添加锁,一个事务在操作数据时,另一个事务等待事务操作完成后才能操作这个表。是最安全的,同时也是效率最低的 |
⑤事务回滚
rollback_for=“java.lang.Exception(异常类型全限定路径)” | 当出现什么异常时需要进行回滚。建议:给定该属性值,手动抛异常,一定给要给该属性值 |
---|---|
no-rollback-for=”异常类型全限定路径” | 表示当出现什么异常时不回滚事务 |