Date: 2017-11-15 00:00:01
spring-事务(五)
文章说明:本文不会只做复制粘贴的动作,在讨论一个问题的时候,理论部分总是词不达意,所以会从网上找合适的描述文章作为本篇的开篇,后续的深入讨论基本都是自己实践经验所得。
先来看一下spring整块的逻辑图
前言
对于spring事务,我将分两大部分部分讲解:
- 事务的基本配置与实践:申明式事务,编程式事务。
- 事务内部处理:数据库隔离级别,事务的传播性;
sping事务概述(转载)
事务一般发生在和持久层打交道的地方,比如数据库。
假设一个工作由两件事共同组成,那么这两件事要么全部完成,这个工作才算完成。要么全部回退到初始状态。不存在只完成一件,还有一件事没完成的。这项工作可称为一个事务。常用的场景就是银行转账。A向B转账100元这项工作由两件事组成:A帐户减100元,B账户加100元。这两件事要么同时完成,要么同时都回退到初始状态。如果只完成其中一件,另一件没完成,那就出岔子了。。
事务有四个特性:ACID
- 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
- 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
- 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
- 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
事务的大概基本原理
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:
1.获取连接 Connection con = DriverManager.getConnection()
2.开启事务con.setAutoCommit(true/false);
3.执行CRUD
4.提交事务/回滚事务 con.commit() / con.rollback();
5.关闭连接 conn.close();
使用Spring的事务管理功能后,我们可以不再写步骤1,2,3 和 4,5 的代码,而是由Spirng 自动完成。后面将会讲解原理
真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
mysql的数据处理引擎如果是MyISAM的话,则事务无效,因为该引擎不支持数据库事务。
spring编程式事务管理器
spring有申明式事务,编程式事务,都是通过管理器来完成了,只是各自封装了一下,方便用户调用而已。
Spring提供了许多内置事务管理器实现:
- DataSourceTransactionManager:位于org.springframework.jdbc.datasource包中,数据源事务管理器,提供对单个javax.sql.DataSource事务管理,用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事务管理;
- HibernateTransactionManager:位于org.springframework.orm.hibernate3包中,提供对单个org.hibernate.SessionFactory事务支持,用于集成Hibernate框架时的事务管理;该事务管理器只支持Hibernate3+版本,且Spring3.0+版本只支持Hibernate3.2+版本;
- JpaTransactionManager:位于org.springframework.orm.jpa包中,提供对单个javax.persistence.EntityManagerFactory事务支持,用于集成JPA实现框架时的事务管理;
- JtaTransactionManager:位于org.springframework.transaction.jta包中,提供对分布式事务管理的支持,并将事务管理委托给Java EE应用服务器事务管理器;
- JdoTransactionManager:位于org.springframework.orm.jdo包中,提供对单个javax.jdo.PersistenceManagerFactory事务管理,用于集成JDO框架时的事务管理;
- OC4JjtaTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对OC4J10.1.3+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持;
- WebSphereUowTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对WebSphere 6.0+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持;
- WebLogicJtaTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对WebLogic8.1+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持。
spring事务实战-基本配置
spring声明式事务
第一种配置:单独开启事务
单独开启为需要手动加入@Transactional来告诉spring这个方法或者类需要加入事务。
在spring配置文件的applicationContext.xml中设置:
第一步:在配置文件中开启事务
<!--1. 配置数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--2. 设置事务实例-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--3. 添加事务,开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
第二步:应用事务
@Transactional 告诉spring则个方法需要添加事务增强功能。
@Transactional
public void serviceFG() {
userInfoExtendService.serviceG();
try {
userInfoExtendService.serviceF();
} catch (Exception e) {
//e.printStackTrace();
}
}
这样一个简单的事务就完成了。
Transactional说明
参数名称 | 功能描述 |
---|---|
readOnly | 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true) |
rollbackForClassName | 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。指定单一异常类名称:@Transactional(rollbackForClassName=”RuntimeException”),指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”}) |
rollbackFor | 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class),指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class}) |
noRollbackFor | 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class),指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class}) |
noRollbackForClassName | 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})readOnly |
propagation | 该属性用于设置事务的传播行为 |
isolation | 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置 |
timeout | 该属性用于设置事务的超时秒数,默认值为-1表示永不超时 |
全局事务配置
在spring配置文件的applicationContext.xml中设置:
<!--1. 配置数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--2. 设置事务实例-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--3. 添加事务,开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--4. 设置全局事务范围-->
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* com.spring.test.*.service.*.*(..)) || execution(* com.spring.test.*.business.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
</aop:config>
<!-- 5. 设置请求类型-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<!--<tx:method name="get*" read-only="true"/>-->
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
com.spring.test.*.service.*.*(..) 这个表示com.spring.test.* 这个包下所有的包,在这个所有包下面的sercie包下的所有包下的所有方法都添加事务。
*:代表一层文件夹;
*():代表任意方法。也可以service*(..);
(..):表示方法的任意参数。
对于这种正则表达式不懂的,可以看spring aop正则表达式。
第二步:代码
package com.spring.test.service.impl;
public void serviceFG() {
userInfoExtendService.serviceG();
try {
userInfoExtendService.serviceF();
} catch (Exception e) {
//e.printStackTrace();
}
}
由于该方法在上面配置的表达式中,所以serviceFG不用添加注解也拥有了事务哦。
上面都是对jdbc的事务配置,hibernate与jpa等其他事务的配置
spring编程式事务
手动编写spring事务
<!--数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--使用jdbc模板操作数据库-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<!--设置dao,用来操作数据库的-->
<bean id="userInfoDao" class="com.test.spring.dao.impl.UserInfoDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!--设置事务实例-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="userInfoExtendService" class="com.test.spring.service.impl.UserInfoExtendServiceImpl">
<property name="userInfoDao" ref="userInfoDao"/>
<!--第一种编程式事务-->
<property name="txManager" ref="transactionManager"/>
<property name="txDefinition">
<bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
</bean>
</property>
<!--第二种编程式事务,使用模版的方式,和第一种是一样的,只不过template封装了第一种方式而已,使用更方便而已-->
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
第二步代码:
public class UserInfoExtendServiceImpl{
private UserInfoDao userInfoDao;
private TransactionDefinition txDefinition;
private PlatformTransactionManager txManager;
private TransactionTemplate transactionTemplate;
public PlatformTransactionManager getTxManager() {
return txManager;
}
public void setTxManager(PlatformTransactionManager txManager) {
this.txManager = txManager;
public void setTxDefinition(TransactionDefinition txDefinition) {
this.txDefinition = txDefinition;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void setUserInfoDao(UserInfoDao userInfoDao) {
this.userInfoDao = userInfoDao;
}
//第一种,纯手动编写
public void serviceJ() {
TransactionStatus txStatus = txManager.getTransaction(txDefinition);
try {
UserInfoVo infoVo = new UserInfoVo();
infoVo.setAge(1000);
infoVo.setUserName("J");
userInfoDao.save(infoVo);
txManager.commit(txStatus);
} catch (Exception e) {
txManager.rollback(txStatus);
System.out.println("Transfer Error!");
}
}
//第二种,使用模版管理
public boolean transfer() {
return (Boolean) transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
Object result = true;
try {
UserInfoVo infoVo = new UserInfoVo();
infoVo.setAge(1000);
infoVo.setUserName("transfer");
userInfoDao.save2(infoVo);
} catch (Exception e) {
status.setRollbackOnly();
result = false;
System.out.println("Transfer Error!");
}
return result;
}
});
}
}
参考
http://blog.csdn.net/soonfly/article/details/70304793(事务理论)
http://www.uml.org.cn/j2ee/201610201.asp
https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/