事务的传播规则:
在一个事务方法中调用了其他的事务方法,此时事务该如何传递,按照什么规则传递
例如有两个service,A和B
A service类 | B service类
|
private serviceB SB; |
public void AAA(){ | public void BBB(){
TODO | TODO
SB.BBB(); |
} | }
Aservice中的业务方法,调用了Bservice中的方法,同时两个业务方法中又有不同的事务操作,
问题来了,那他们的事务该怎么运行传递呢?
//事务传播规则
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
第一种情况:需要尊重/尊从当前事务
REQUIRED:必须的意思,必须存在一个事务,则加入到该事务中,否则,新建一个事务,使用比较多的情况。
比如,在AAA()中调用BBB(),AAA()中存在事务,则就使用该事务,不存在,则BBB()新建一个事务。
SUPPORTS:支持,如果当前有事务,则使用该事务,如果当前没有事务,则以非事务的方式运行。
比如,在AAA()中调用BBB(),AAA()中存在事务,则就使用该事务,AAA()不存在事务,则不使用事务运行BBB()。
MANDATORY:必须存在事务,如果当前存在事务,就是用该事务,否则,就会出现非法事务异常(IIlegalTranactionStatusException)
第二种情况:不尊从当前事务
REQUIRES_NEW:不管当前是否存在事务,都会开启一个事务,必须是一个新的事务,在开发中使用的比较多,根据业务的情况。
NOT_SUPPORTED:一定要以非事务的方式执行,如果当前存在事务,就会把当前的事务挂起。
比如,在AAA()中调用BBB(),AAA()中存在事务,在BBB()中不要事务,则该事务进行挂起,等AAA()调用完BBB(),
又回到AAA()的时候 又拿着之前的事务来用。我们用的不多
NEVER:不支持事务,如果当前存在事务,马上抛出异常(IIlegalTranactionStatusException),不能有事务,有事务就报异常
情况三:寄生事务(外部事务/内部事务/嵌套事务)
NESTED:寄生事务,如果当前存在事务,则在内部事务内执行,
如果当前不存在事务,则创建一个新的事务。
寄生事务可以通过数据库的savePoint(保存点)来实现,寄生事务可以回滚回来,
但是他们的回滚不影响外部事务,但是外部事务的回滚会影响寄生事务。
在以后的开发过程中用的不多
//隔离级别
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
//事务超时时间
int TIMEOUT_DEFAULT = -1;
事务管理: 数据源:数据库
案例:银行转账
Spring的事务增强
XML形式:
事务三步骤:what when where
第一步:what--做什么增强! 事务管理器(配置一个id,取个名字) 引入一个连接池对象(DataSource)
<bean id="trans" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="DataSource"/>
</bean>
第二步:when--什么时机做增强,环绕增强(配置一个id,取个名字)--表现的是在什么时机做增强---前提的引入tx的命名空间
<tx:advice id="txAdvice" transaction-manager="trans">//transaction-manager有一个默认值:transactionManager,
<tx:attributes>
<tx:method name="Change"/>
</tx:attributes>
</tx:advice>
2 when 和 1 what,要进行关联,如果不关联的话,就会出现各干各的,没有关联,那就没有意义了,所以环绕增强要和事务管理器进行关联,环绕增强内包含一个事务管理器.
(1)transaction-manager有一个默认值:transactionManager,这个属性和值可以不写,不写的话,what中的事务管理器的id要改为transactionManager。
(2)如果自定义事务管理器的id的话,环绕增强的事务管理的值,一定是事务管理器自定义的名字.dataSource id="trans"-->transaction-manager="trans".
(3)对事务增强的属性配置(tx:attributes):里面可以存在多个tx:method,表示哪些方法要做事务增强。--业务层。
第三步:where --在什么范围做事务增强, 配置切面(aop)
<aop:config>
<aop:pointcut expression="execution(* Spring_Data.transforMoney.*(..))" id="txpc"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txpc"/>
</aop:config>
2 when 和 3 where要进行关联,
(1)配置一个aop:pointcut,首先给aop:pointcut取个名字(txpc),然后在配置一个表达式,表示事务增强的作用域。
(2)配置一个aop:advisor,有两个属性,advice-ref:属性的值为环绕增强的ID值,要进行关联(3 where 和2 when要进行关联)
pointcut-ref:属性的值为切点的ID值,这样切点aop:pointcut又和aop:advisor关联起来了。
最终:归结点在于事务增强的作用域和作用域之内的方法
aop:pointcut-->aop:advisor-->tx:advice-->DataSourceTransactionManager:穿成一条线。
事务管理器之环绕增强的属性:<tx:method/>的属性值
<tx:attributes>
<tx:method name="Change"/>
</tx:attributes>
name 必填 要进行事务管理的方法名称,支持通配符方式:*,匹配方法的模式(Change*):例如Changexxx、Changeaaa。。。。
propagation 非必填 事务的传播规则
- REQUIRED 默认值
- SUPPORTS
- MANDATORY
- REQUIRES_NEW
- NOT_SUPPORTED
- NEVER
isolation 非必填 隔离级别 建议使用默认值,其他四种是Spring模拟出来的,我们一般不用。我们用DEFAULT不会使用
- DEFAULT 默认值
- READ_UNCOMMITTED
- READ_COMMITTED
- REPEATABLE_READ
- SERIALIZABLE
timeout 非必填 事务超时时间
- -1 默认值
read-only 非必填 是否是只读事务 比如在hibnate中设置read-only=“true”可以提高性能,一般只有查询的时候 我们可以设置为true,
可以提高性能
rollback-for 非必填 因为什么做事务回滚 遇到什么异常进行回滚
当我们在业务方法中抛出了一个runtimeException异常,事务就要回滚,抛给用户看,
并让用户知道之前的操作统统给取消掉。多个异常的时候可以使用逗号隔开 rollback-for="Exception,Exception"
- java.lang.RuntimeException 默认值
no-roback-for 非必填 遇到什么异常不回滚
配置方法属性的规则
首先在创建业务方法的时候 要遵循一定的方法命名规范
然后在配置方法的属性的时候使用名称的前缀+*
比如查询操作
<tx:method name="get*" read-only=“true”/>
<tx:method name="list*" read-only=“true”/>
<tx:method name="query*" read-only=“true”/>
//*非查询方法
<tx:method name="*"/>
配置事务(****)增强的流程图:
首先明确 三部分 1.事务管理器(what) 2.AOP切面(where) 3.事务增强(when)
1 <bean id="a" TXmanager/>
2 <aop:config>
<aop:pointcut excution="(* 包.子包.类.*(**))" id="c" >
<aop:advicer pointcut-ref="c" advice-ref="b">
</aop:config>
3 <tx:advice id="b" mage="a"
<tx:methed=""