1 什么是事务
1 保证一组操作,要么全部成功,要么全部失败
2 事务的特性
提到事务特性,肯定会想起ACID特性.
原子性(Atomicity): 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
一致性(Consistency): 执行事务前后,数据保持一致;
隔离性(Isolation): 并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的;
持久性(Durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
3 Spring 中事务
在Spring中,事务抽象的关键接口是org.springframework.transaction.PlatformTransactionManager.

PlatformTransactionManager 的主要实现类大致如下:
- DataSourceTransactionManager:适用于使用JDBC和iBatis进行数据持久化操作的情况。
- HibernateTransactionManager:适用于使用Hibernate进行数据持久化操作的情况。
- JpaTransactionManager:适用于使用JPA进行数据持久化操作的情况。
- 另外还有JtaTransactionManager 、JdoTransactionManager、JmsTransactionManager等等。
TransactionDefinition接口:定义事务信息(事务隔离,传播特性,超时,只读状态)
定义的主要属性(虽然spring官方文档只定义了三种传播特性,但是代码中是有七种特性):

TransactionStatus接口: 为事务提供了一种简单的方法来控制事务执行和查询事务状态
定义的主要方法:

4 Spring事务的传播特性
Spring共支持7种传播行为:
PROPAGATION_REQUIRED:如果当前存在事务,就用当前事务;如果当前没有事务,则创建一个新的事务。是Spring默认的传播行为。
PROPAGATION_REQUIRES_NEW:创建一个新的事务,无论是否有事务
PROPAGATION_SUPPORTS: 事务可有可无
PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
PROPAGATION_MANDATORY:当前如果存在事务,则加入该事务;当前没有事务,则抛出异常。(强制性)
PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价PROPAGATION_REQUIRED。嵌套事务使用数据库中的保存点来实现,即嵌套事务回滚不影响外部事务,但外部事务回滚将导致嵌套事务回滚。
5 Spring中的事务隔离级别

6 spring事务使用
工具:IDEA2018 ,
环境说明:spring boot(2.1.7),jdk1.8
在spring 是事务主要使用方式有两种。
1 编程式事务
用过 Hibernate 的人都知道,我们需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
Spring Framework提供了两种编程式事务管理方法:
- 使用
TransactionTemplate。 PlatformTransactionManager使用.
TransactionTemplate 使用如下:
@Autowired
private TransactionTemplate transactionTemplate;
/**
* 使用手动事务管理
*/
private void handTransaction() {
//如果没有返回值可以使用TransactionCallbackWithoutResult
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
jdbcTemplate.execute("INSERT into cat(name ) values('黑猫')");
log.info("查询是否插入黑猫:{}", getCount());
transactionStatus.setRollbackOnly();
}
});
log.info("查询是否插入黑猫:{}", getCount());
//如果有返回值可以使用TransactionCallback
Object obj= transactionTemplate.execute(new TransactionCallback(){
@Override
public Object doInTransaction(TransactionStatus transactionStatus) {
jdbcTemplate.execute("INSERT into cat(name ) values('黑猫')");
log.info("查询是否插入黑猫:{}", getCount());
transactionStatus.setRollbackOnly();
return 1;
}
});
log.info("返回值:{}",obj);
}
PlatformTransactionManager使用

2 声明式事务
Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
简单创建一个spring boot项目

上面我使用h2一个内存数据库
package com.example.demo03;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.annotation.Resource;
@SpringBootApplication
@Slf4j
public class Demo03Application implements CommandLineRunner {
@Resource
private CatService catService;
@Autowired
private JdbcTemplate jdbcTemplate;
public static void main(String[] args) {
SpringApplication.run(Demo03Application.class, args);
}
/**
* spring boot容器开启后,会自动运行run方法
* @param args
* @throws Exception
*/
@Override
public void run(String... args) throws Exception {
initDatasource();
}
/**
* 记录下当前使用事务管理器
*/
private void initDatasource(){
DataSourceTransactionManager txManager = new DataSourceTransactionManager(jdbcTemplate.getDataSource());
log.info("事务:{}",txManager);
}
}
上面代码验证了下当前使用事务管理器

下面一个service验证下@Transactional使用,下面是我的项目结构

CatService代码:
/**
* @author 疯信子
* @version 1.0
* @date 2019/8/9.
*/
public interface CatService {
public void insertCat() throws MyException;
public void insertCatMany();
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* @author 疯信子
* @version 1.0
* @date 2019/8/9.
*/
@Component
public class CatServiceImpl implements CatService {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
*
*/
@Override
@Transactional
public void insertCat() throws MyException {
jdbcTemplate.execute("insert into cat(name) values ('黑猫')");
throw new MyException();
}
@Override
public void insertCatMany() {
}
}
@Transactional 默认属性:
1 传播设置是 PROPAGATION_REQUIRED.
2 隔离级别是 ISOLATION_DEFAULT.
3所有RuntimeException触发器回滚,任何检查Exception都不会回滚
如果需要回滚对应Excepiton事务可以在@Transactional使用 rollbackFor
Spring 官网文档暂时只介绍三种事务传播特性(required,requires_new,nested)。 实际是有7种事务传播特性.
代码如下
/**
*
*/
@Override
@Transactional
public void insertCat() throws MyException {
try {
jdbcTemplate.execute("insert into cat(name) values ('黑猫')");
throw new MyException();
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
@Override
public void insertCatMany() {
try {
insertCat();
// catService.insertCat();
} catch (MyException e) {
log.error("系统异常", e);
}
}
}
事务常见的错误:
一 No transaction aspect-managed TransactionStatus in scope

出现这个错误的原因是:
在于AOP的实现原理。由于@Transactional 的实现原理是AOP,AOP的原理是动态代理,换句话说,自调用时不存在代理对象的调用,这时不会产生我们注解@Transactional 配置的参数,自然无效了。
解决方案有一下两种
1 在没有@Transactional 通过注入servcie

2在insertCatMany方法中添加@Transactional注解
二 Transaction rolled back because it has been marked as rollback-only

而fooService里写的代码如下:

这里导致的问题,事务的嵌套,FooService.insertFoo()使用默认的传播特性(PROPAGATION_REQUIRED)导致.
PROPAGATION_REQUIRED具体意思可以参考上面说明
要想解决这个问题,可以直接修改传播特性为PROPAGATION_REQUIRES_NEW。这样就是嵌套的代码回滚,而外面的代码不回滚。
以上是关于spring事务的思考
1284



被折叠的 条评论
为什么被折叠?



