MySQL事务通过简单的Sql语句就可以开启提交或回滚事务,实际使用中特别是Spring对事务的封装,可以让我们通过声明或注解的方式就可以控制事务,还可以支持事务的嵌套、传播。为了理解这样的事务设计,还需要从基本的Sql事务控制开始入手。虽然spring提供了更强大更灵活的事务控制方式,不过有些开发者也许更喜欢原生的事务控制方式,因为这用起来清晰明了。也不需要增加对Spring事务设计学习的成本。
原生SQL事务开启方式
SET [GLOBAL | SESSION] TRANSACTION
transaction_characteristic [, transaction_characteristic] ...
transaction_characteristic:
ISOLATION LEVEL level
| READ WRITE
| READ ONLY
level:
REPEATABLE READ
| READ COMMITTED
| READ UNCOMMITTED
| SERIALIZABLE
注意:MySQL本身是不支持嵌套事务的。在MySQL中开启一个事务后,如果在为提交前又开启了一个事务,则MySQL会自动提交当前事务。而Spring在实现嵌套事务时是通过SavePoint实现。SavePoint介绍:http://dev.mysql.com/doc/refman/5.7/en/savepoint.html
MySQL JDBC事务操作方式
Connection conn = DriverManager.getConnection(dbURL,dbUser,dbPassword);
conn.setAutoCommit(false);
try(Connection conn = DriverManager.getConnection(dbURL,dbUser,dbPassword);){
conn.setAutoCommit(false);
// perform operations such as insert, update, delete here
// ..
// if everything is OK, commit the transaction
conn.commit();
} catch(SQLException e) {
// in case of exception, rollback the transaction
conn.rollback();
}
Spring事务操作:以DataSourceTransactionManage为例
<!--事务配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
// 编程中实际事务的使用方式
public void insert(User user) {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 设置事务的名字
def.setName("UserService.insertUser");
// 设置事务的传播属性
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
userDao.insertUser(user);
txManager.commit(status);
} catch (Exception ex) {
txManager.rollback(status);
throw new RuntimeException(ex);
}
}
这种在数据源上控制事务的方式设计是在请求的当前线程范围内,从数据中获取一个connection对象,底层通过JDBC的方式操作当前connection的事务,是对原生JDBC的一种封装方式。所以这种事务的有效范围也只限于当前请求中的一个connection。在实际使用中,也许不会像上面这样通过编程的方式控制事务,一般会采用AOP或者加注解的方式,这种方式我们称之为声明式事务控制,原理也是一样,只是采用代理的方式帮我们省去了这些基本上都是重复的事务控制逻辑。
在Spring的事务实现中,PlatformTransactionManager是各种类型的事务的顶层抽象API,下面是Spring事务的类图
Spring事务传播属性配置
传播属性 | 描述 | 备注 |
---|---|---|
required | 如果当前没有事务就打开一个新的 | |
requires new | 新建事务,如果存在事务就把当前事务挂起 | 挂起对应的底层操作是:为当前事务新创建一个connection |
support | 如果当前有事务,就在事务中执行,如果没有就以非事务的方式执行 | |
never | 以非事务的方式运行,如果有事务则抛出异常 | |
not supported | 以非事务的方式运行,如果当前存在事务则挂起当前事务 | |
nested | 如果当前有事务,则在嵌套内执行,如果没有和required 一样 | mysql是不支持嵌套事务的,它是通过MySQL提供的SavePoint功能实现 |
mandatory | 使用当前的事务,如果没有就抛出异常 |
另外需要注意的地方:如果采用AOP或者注解这种方式,即声明式事务方式,在同一个类中,A方法调用B方法这种情况下,B方法的事务声明并不会生效:http://stackoverflow.com/questions/18590170/transactional-does-not-work-on-method-level
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。