一、spring的事务管理
1、引出事务的经典例子:银行转账发生异常
✿ 解决:把转出钱和转入钱的业务放到同一个事务空间。
■ 分析转账过程流程:
① 首先,获取 DataSource 对象;
② 其次,获取 DataSource 中的 Connection 对象;
③ 接着,设置取消事务的自动提交方式: connection.setAutoCommit(false);
④ 然后,
把 connection 绑定到当前线程中;
⑤
从当前线程中获取 Connection 对象
⑥ 如果正常执行,则提交事务:提交事务:connection.commit(); 如果出现异常,则回滚事务:回滚事务:connection.rollback();
2、Spring 的事务管理主要包括 3 个:PlatformTransactionManager、TransactionDefinition、TransactionStatus
-
PlatformTransactionManager:根据 TransactionDefinition 提供的事务属性配置信息,
创建事务
。
-
TransactionDefinition:
封装事务的隔离级别和超时时间
,是否为只读事务和事务的隔离级别和传播规则等
事务属性
.
-
TransactionStatus:
封装了事务的具体运行状态
。如是否是新开启事务,是否已经提交事务,设置当前事务为rollback-only.
■ PlatformTransactionManager
✿ 记:常用的事务管理器:
-
JDBC/MyBatis:DataSourceTransactionManager
-
Hibernate: HibernateTransactionManager
3、事务传播规则 TransactionDefinition
(1)事务的传播规则(传播行为):
在一个事务方法中,调用了其他事务的方法,此时事务该如何传递,按照什么规则传播.
(2)传播规则适应的情况:
■ 情况一:需要尊重/遵从当前事务
-
REQUIRED:(
常用
)必须存在一个事务,如果当前存在一个事务,则加入到该事务中,否则,新建一个事务.
-
SUPPORTS:支持当前事务,如果当前存在事务,则使用该事务,否则,以非事务形式运行.
-
MANDATORY:必须要存在事务,如果当存在事务,就使用该事务,否则,非法的事务状态异常:(IllegalTranactionStatusException)
■ 情况二:不遵从当前事务的
- REQUIRES_NEW:(
常用
)不管当前是否存在事务,都会新开启一个事务.必须是一个新的事务. - NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,把当前事务挂起(暂停).
- NEVER:不支持事务,如果当前存在事务,抛出一个异常.
■ 情况三:寄生事务(外部事务/内部事务/嵌套事务)
-
NESTED:寄生事务,如果当前存在事务,则在内部事务内执行.如果当前不存在事务,则创建一个新的事务.
寄生事务可以通过数据库savePoint(保存点)来实现,奇生事务可以回滚的,但是他的回滚不影响外部事务.但是外部事务的回滚会影响寄生事务.
寄生事务并不是所有的事务管理器都支持,比如HibernateTransactionManager默认就不支持,需要手动去开启.
-
Jdbc和MyBatis的事务管理器:DataSourceTransactionManager:默认就是支持的.
二、事务配置
1、使用xml配置jdbc事务
<!-- ===============好比是AOP,事务增强================================== --><!-- 1、what:配置jdbc事务管理器 --><bean id=\"txManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\"><property name=\"dataSource\" ref=\"dataSource\"/></bean><!-- 2:when:配置事务管理器增强(环绕增强) --><!-- 关联what --><tx:advice id=\"txAdvice\" transaction-manager=\"txManager\"><tx:attributes><tx:method name=\"trans\"/></tx:attributes></tx:advice><!-- 3、where:配置切面 --><!-- 关联when --><aop:config><aop:pointcut id=\"txPc\" expression=\"execution(* com.shan.service.*Service.*(..))\" /><aop:advisor advice-ref=\"txAdvice\" pointcut-ref=\"txPc\"/></aop:config>
2、事务增强的属性配置 <tx:method/> 元素的属性:
属性 | 必要? | 默认 | 描述 |
---|---|---|---|
name 匹配方法的模式 | 是 | ||
propagation 事务的传播规则 | 否 | required | |
isolation 事务的隔离级别 | 否 | default | DEFAULT:使用数据库自身设置的隔离级别,其他四种都是Spring通过java代码模拟出来的 |
timeout 事务超时时间 | 否 | -1 | 缺省 -1 表示使用底层数据库自身的超时时间 |
read-only 是否是只读事务 | 否 | false | 若对于查询方法,设置只读,会提高性能,例如Hibernate |
rollback-for 遇到什么异常做回滚 | 否 | java.lang.RuntimeException | 当我们在业务方法中,抛出一个Runtime异常,则事务回滚。自定义异常,若是需要配置多个异常,使用,隔开 |
no-rollback-for 遇到什么异常不做回滚 | 否 |
3、使用注解配置jdbc事务
-
注解:@Transactional
-
注解属性:name、propagation、isolation、timeout、read-only、rollback-for、no-rollback-for
-
注解第三方解析:
<bean id=\"txManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\"><property name=\"dataSource\" ref=\"dataSource\"></property></bean><!-- tx注解解析器 --><tx:annotation-driven transaction-manager=\"txManager\"/>
■ 注解@Transactional使用:
@Service@Transactionalpublic class AccountServiceImpl implements IAccountService{@Autowiredprivate IAccountDAO dao;@Overridepublic void trans(Long outId, Long inId, int money) {dao.transOut(outId, money);int a = 1/0; //算术异常dao.transIn(inId, money);}//若是有查询方法,可以再贴注解@Transactional添加注解属性@Transactional(readOnly = true)public void listXX() {}}
4、Java Config 配置
@Configuration 配置
@import(配置子类)
@Bean 配置创建bean对象
@ComponentScan ioc注解解析器
@EnableTransactionManagement 事务注解解析器
■ DataSourceConfig.java
//当前项目的连接池的配置类@Configuration@PropertySource(\"classpath:db.properties\")public class DataSourceConfig {@Value(\"${jdbc.driverClassName}\")private String driverClassName;@Value(\"${jdbc.url}\")private String url;@Value(\"${jdbc.username}\")private String username;@Value(\"${jdbc.password}\")private String password;@Value(\"${jdbc.initialSize}\")private int initialSize;//配置连接池的Bean@Beanpublic DataSource dataSource() {DruidDataSource ds = new DruidDataSource();ds.setDriverClassName(driverClassName);ds.setUrl(url);ds.setUsername(username);ds.setPassword(password);ds.setInitialSize(initialSize);return ds;}}
■ AppConfig.java
//当前项目的配置类,好比是pplicationContext.xml@Configuration //标识当前类为一个配置类@Import(DataSourceConfig.class) //包含其他的配置类@ComponentScan //ioc注解解析器【di注解解析器默认是导入的】@EnableTransactionManagement//事务注解解析器public class AppConfig {//创建事务管理的Bean@Beanpublic DataSourceTransactionManager txManager(DataSource ds) {return new DataSourceTransactionManager(ds);}}
■ App.java
@SpringJUnitConfig(classes = AppConfig.class)public class App {@Autowiredprivate IAccountService service;@Testvoid testTrans() throws Exception {service.trans(1L, 2L, 100);}}