目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

Spring 事务抽象

Spring 的事务抽象

 Spring 为数据访问层提供了很多抽象,在这些抽象下面我们可以非常方便的使用统一的方式来操作不同的框架。
 Spring 的事务抽象采用了一致的事务模型,方便你使用不同的

  • JDBC/Hibernate/myBatis
  • DataSource/JTA

事务抽象的核心接口

 不同框架的事务管理器都现了 AbstractPlatformTransactionManager,AbstractPlatformTransactionManager 实现了 PlatformTransactionManager,所以 PlatformTransactionManager 的实现类可以是以下类

  • DataSourceTransactionManager
  • HibernateTransactionManager
  • JtaTransactionManager
1public interface PlatformTransactionManager {
2	//TransactionStatus 获取事务状态,TransactionDefinition用于设置事务传播特性、隔离级别、超时设置、是否只读。
3	TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
4
5	void commit(TransactionStatus status) throws TransactionException;
6
7	void rollback(TransactionStatus status) throws TransactionException;
8}

事务传播行为

事务传播特性

REQUIRES_NEW 对比 NESTED

  • REQUIRES_NEW:两个事物没有关联。
  • NESTED:两个事物有关联、外部事物回滚、内嵌事物也会回滚。

事务隔离级别

事务隔离级别

编程式事务

 TransactionTemplate 继承了 DefaultTransactionDefinition,所以所有事务相关的属性都可以直接设置给 TransactionTemplate.

TransactionTemplate

  • TransactionCallback():有返回值的操作。
  • TransactionCallbackWithoutResult():没有返回值的操作。

如何设置事务的特性

  • TransactionTemplate 中可以设置当前事务的播特性和隔离特性
  • 另外在定义 PlatfromTransactionManager 的时候可以传入 TransactironDefinition 进行定义前事务的播特性和隔离特性。
1TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;

编程式事务示例

 1package geektime.spring.data.programmatictransactiondemo;
 2
 3import lombok.extern.slf4j.Slf4j;
 4import org.springframework.beans.factory.annotation.Autowired;
 5import org.springframework.boot.CommandLineRunner;
 6import org.springframework.boot.SpringApplication;
 7import org.springframework.boot.autoconfigure.SpringBootApplication;
 8import org.springframework.jdbc.core.JdbcTemplate;
 9import org.springframework.transaction.TransactionStatus;
10import org.springframework.transaction.support.TransactionCallbackWithoutResult;
11import org.springframework.transaction.support.TransactionTemplate;
12
13@SpringBootApplication
14@Slf4j
15public class ProgrammaticTransactionDemoApplication implements CommandLineRunner {
16	@Autowired
17	private TransactionTemplate transactionTemplate;
18	@Autowired
19	private JdbcTemplate jdbcTemplate;
20
21	public static void main(String[] args) {
22		SpringApplication.run(ProgrammaticTransactionDemoApplication.class, args);
23	}
24
25	@Override
26	public void run(String... args) throws Exception {
27		//设置传播行为(默认是PROPAGATION_REQUIRED)
28		transactionTemplate.setPropagationBehavior(0);
29		//设置隔离级别(默认是ISOLATION_DEFAULT:使用的是底层数据库的默认的隔离级别)
30		transactionTemplate.setIsolationLevel(3);
31		//设置是否只读
32		transactionTemplate.setReadOnly(true);
33		//设置超时时间(默认)
34		transactionTemplate.setTimeout(30000);
35
36		log.info("COUNT BEFORE TRANSACTION: {}", getCount());// COUNT BEFORE TRANSACTION: 0
37		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
38			@Override
39			protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
40				jdbcTemplate.execute("INSERT INTO FOO (ID, BAR) VALUES (1, 'aaa')");
41				log.info("COUNT IN TRANSACTION: {}", getCount());// COUNT IN TRANSACTION: 1
42				transactionStatus.setRollbackOnly();//设置事务为rollback
43			}
44		});
45		log.info("COUNT AFTER TRANSACTION: {}", getCount());// COUNT AFTER TRANSACTION: 0
46	}
47
48	private long getCount() {
49		return (long) jdbcTemplate.queryForList("SELECT COUNT(*) AS CNT FROM FOO")
50				.get(0).get("CNT");
51	}
52}

声明式事务

@Transactional

  • transactionManager
  • propagation
  • isolation
  • timeout
  • readOnly
  • 判断回滚:当碰到特定的异常类时,才会进行回滚。

FooService

1package geektime.spring.data.declarativetransactiondemo;
2
3public interface FooService {
4    void insertRecord();
5    void insertThenRollback() throws RollbackException;
6    void invokeInsertThenRollback() throws RollbackException;
7}

FooServiceImpl

 1package geektime.spring.data.declarativetransactiondemo;
 2
 3import org.springframework.aop.config.AopConfigUtils;
 4import org.springframework.aop.framework.AopContext;
 5import org.springframework.beans.factory.annotation.Autowired;
 6import org.springframework.jdbc.core.JdbcTemplate;
 7import org.springframework.stereotype.Component;
 8import org.springframework.transaction.annotation.Transactional;
 9
10@Component
11public class FooServiceImpl implements FooService {
12    @Autowired
13    private JdbcTemplate jdbcTemplate;
14
15    @Autowired
16    private FooService fooService;
17
18    @Override
19    @Transactional
20    public void insertRecord() {
21        jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('AAA')");
22    }
23
24    @Override
25    //@Transactional(rollbackFor = RollbackException.class, propagation = Propagation.REQUIRES_NEW)
26    @Transactional(rollbackFor = RollbackException.class)
27    public void insertThenRollback() throws RollbackException {
28        jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('BBB')");
29        throw new RollbackException();
30    }
31
32    /**
33     * AopContext.currentProxy() 可以获取当前类的代理类,命中切点
34     */
35    @Override
36    public void invokeInsertThenRollback() throws RollbackException {
37        //((FooService) AopContext.currentProxy()).insertThenRollback();
38        fooService.insertThenRollback();
39    }
40}

RollbackException

1package geektime.spring.data.declarativetransactiondemo;
2
3public class RollbackException extends Exception {
4}

启动类

 1package geektime.spring.data.declarativetransactiondemo;
 2
 3import lombok.extern.slf4j.Slf4j;
 4import org.springframework.beans.factory.annotation.Autowired;
 5import org.springframework.boot.CommandLineRunner;
 6import org.springframework.boot.SpringApplication;
 7import org.springframework.boot.autoconfigure.SpringBootApplication;
 8import org.springframework.context.annotation.AdviceMode;
 9import org.springframework.jdbc.core.JdbcTemplate;
10import org.springframework.transaction.annotation.EnableTransactionManagement;
11
12@SpringBootApplication
13//开启事务注解的支持
14@EnableTransactionManagement(mode = AdviceMode.PROXY)
15@Slf4j
16public class DeclarativeTransactionDemoApplication implements CommandLineRunner {
17	@Autowired
18	private FooService fooService;
19	@Autowired
20	private JdbcTemplate jdbcTemplate;
21
22	public static void main(String[] args) {
23		SpringApplication.run(DeclarativeTransactionDemoApplication.class, args);
24	}
25
26	@Override
27	public void run(String... args) throws Exception {
28		//insertRecord()
29		fooService.insertRecord();
30		log.info("AAA {}",
31				jdbcTemplate
32						.queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='AAA'", Long.class));//AAA 1
33
34		//insertThenRollback()
35		try {
36			fooService.insertThenRollback();
37		} catch (Exception e) {
38			log.info("BBB {}",
39					jdbcTemplate
40							.queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='BBB'", Long.class));//BBB 0
41		}
42
43		/**
44		 * invokeInsertThenRollback()
45		 * Spring的声明式事务本质是利用 AOP Proxy,它在目标方法上做了一层封装,进而帮助用户做一些模板式的事务操作。
46		 * 需要直接调用带有@Transaction注解的类才会生成代理类,被同类种其他方法调用则不会生成代理类,所以@Trasaction注解失效
47		 */
48		try {
49			fooService.invokeInsertThenRollback();
50		} catch (Exception e) {
51			log.info("BBB {}",
52					jdbcTemplate
53							.queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='BBB'", Long.class));//BBB 1  正确应该是 BBB 0
54		}
55	}
56}

作者:Soulboy