使用
使用 SpringBoot 建立一个测试项目.
sql
create database test;-- auto-generated definitioncreate table test_transaction(id int auto_incrementprimary key,name varchar(16) default '' not null,email varchar(24) default '' not null,birth timestamp default CURRENT_TIMESTAMP not nullon update CURRENT_TIMESTAMP)engine = InnoDB;
DataSource
/*** @author chenshun00@gmail.com* @since 2019/5/4*/@Configuration@EnableTransactionManagement(proxyTargetClass = true) // 开启事务public class DataSourceConfig implements EnvironmentAware {private Environment environment;@Bean(initMethod = "init", destroyMethod = "close")public DataSource dataSource() {DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setUsername(this.environment.getProperty("spring.datasource.username"));druidDataSource.setPassword(this.environment.getProperty("spring.datasource.password"));druidDataSource.setUrl(this.environment.getProperty("spring.datasource.url"));druidDataSource.setDriverClassName(this.environment.getProperty("spring.datasource.driver-class-name"));druidDataSource.setDbType(this.environment.getProperty("spring.datasource.type"));druidDataSource.setInitialSize(Integer.parseInt(this.environment.getProperty("spring.datasource.initialSize")));druidDataSource.setMaxActive(Integer.parseInt(this.environment.getProperty("spring.datasource.maxActive")));druidDataSource.setMaxWait(Integer.parseInt(this.environment.getProperty("spring.datasource.maxWait")));druidDataSource.setValidationQuery(this.environment.getProperty("spring.datasource.validationQuery"));druidDataSource.setTestWhileIdle(Boolean.parseBoolean(this.environment.getProperty("spring.datasource.testWhileIdle")));druidDataSource.setTestOnBorrow(Boolean.parseBoolean(this.environment.getProperty("spring.datasource.testOnBorrow")));druidDataSource.setTestOnReturn(Boolean.parseBoolean(this.environment.getProperty("spring.datasource.testOnReturn")));return druidDataSource;}@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}}
例子
SQL语句使用
wireshark抓取. 源代码地址: https://github.com/chenshun00/mysql-transaction/
checked异常回滚
- NullPointException
RuntimeException…
set autocommit = 0INSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:20:37.209')rollbackSET autocommit=1@Transactionalpublic void testUncheckedExceptionRollback() {testTransactionDao.addTestTransaction(build());throw new NullPointerException("测试checked异常会滚");}
unchecked异常不回滚
- SQLException
other exception…
set autocommit = 0INSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:20:37.209' )SET autocommit=1@Transactionalpublic void testCheckedException() throws SQLException {testTransactionDao.addTestTransaction(build());throw new SQLException("ggg");}
指定异常回滚
@Transactional(rollbackFor = {SQLException.class})
set autocommit = 0INSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:20:37.209' )rollbackSET autocommit=1@Transactional(rollbackFor = {SQLException.class})public void testCheckedExceptionRollback() throws SQLException {testTransactionDao.addTestTransaction(build());throw new SQLException("ggg");}
嵌套方法(无异常)
--nest method 共插入2条记录 sqlSET autocommit=0select @@session.tx_read_onlyINSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:47:00.572' )select @@session.tx_read_onlyINSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:47:00.635' )commitSET autocommit=1@Transactionalpublic void testNestMethod() {//inserttestTransactionDao.addTestTransaction(build());this.subMethod();}private void subMethod() {testTransactionDao.addTestTransaction(build());}
嵌套方法带checked异常
--子方法出现运行运行时异常,回滚SET autocommit=0select @@session.tx_read_onlySELECT @@session.tx_isolationINSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:57:47.05' )INSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:57:47.141' )rollbackSET autocommit=1@Transactionalpublic void testNestMethodRuntimeException() {testTransactionDao.addTestTransaction(build());this.subExceptionMethod();}private void subExceptionMethod() {testTransactionDao.addTestTransaction(build());throw new NullPointerException("运行时异常测试");}
嵌套方法带unchecked异常.
set autocommit = 1select @@session.tx_read_onlySELECT @@session.tx_isolationset autocommit = 0insert sql语句insert sql语句commitset autocommit = 1@Transactionalpublic void testNestMethodUncheckException() throws SQLException {testTransactionDao.addTestTransaction(build());this.subUncheckExceptionMethod();}private void subUncheckExceptionMethod() throws SQLException {testTransactionDao.addTestTransaction(build());throw new SQLException("运行时异常测试");}
嵌套方法指定异常回滚
set autocommit = 1select @@session.tx_read_onlySELECT @@session.tx_isolationset autocommit = 0insert sql语句insert sql语句rollbackset autocommit = 1@Transactional(rollbackFor = {SQLException.class})public void testNestMethodUncheckExceptionRollback() throws SQLException {testTransactionDao.addTestTransaction(build());this.subUncheckExceptionMethodRollback();}private void subUncheckExceptionMethodRollback() throws SQLException {testTransactionDao.addTestTransaction(build());throw new SQLException("运行时异常测试");}
this 调用无事务
/*** 测试调用未开启事务,直接是一条sql一个事务提交* 没有事务原因:没有Transactional注解,没有进入proxy代理当中,没有进入代码当中就进入不了事务,* this调用还是没有事务,这里如果要产生事务就需要获取当前(this)对象当proxy对象,再进行方法调用会产生事务*/public void testMainMethodNoTransactionRuntimeException() {this.subMethodTransactionRuntimeException();}@Transactionalpublic void subMethodTransactionRuntimeException() {testTransactionDao.addTestTransaction(build());throw new NullPointerException("11");}
this 调用带事务
/*** proxy代理调用产生事务* 需要配置 @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)*/public void testProxyObjectGetTransaction() throws SQLException {((TestTransactionService) AopContext.currentProxy()).testProxyObjectGetTransactionSubMethod();}@Transactional(rollbackFor = {SQLException.class})public void testProxyObjectGetTransactionSubMethod() throws SQLException {testTransactionDao.addTestTransaction(build());throw new SQLException("11");}
多Transactional注解
/*** 事务1* <p>* set autocommit = 0* insert* insert* commit* set autocommit = 1*/@Transactionalpublic void firstTransaction() {testTransactionDao.addTestTransaction(build());this.secondTransaction();}/*** 事务2*/@Transactionalpublic void secondTransaction() {testTransactionDao.addTestTransaction(build());}
总结
自己多试试,抓包看本质.
