使用
使用 SpringBoot
建立一个测试项目.
sql
create database test;
-- auto-generated definition
create table test_transaction
(
id int auto_increment
primary key,
name varchar(16) default '' not null,
email varchar(24) default '' not null,
birth timestamp default CURRENT_TIMESTAMP not null
on 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;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
例子
SQL语句使用
wireshark
抓取. 源代码地址: https://github.com/chenshun00/mysql-transaction/
checked异常回滚
- NullPointException
RuntimeException…
set autocommit = 0
INSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:20:37.209')
rollback
SET autocommit=1
@Transactional
public void testUncheckedExceptionRollback() {
testTransactionDao.addTestTransaction(build());
throw new NullPointerException("测试checked异常会滚");
}
unchecked异常不回滚
- SQLException
other exception…
set autocommit = 0
INSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:20:37.209' )
SET autocommit=1
@Transactional
public void testCheckedException() throws SQLException {
testTransactionDao.addTestTransaction(build());
throw new SQLException("ggg");
}
指定异常回滚
@Transactional(rollbackFor = {SQLException.class})
set autocommit = 0
INSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:20:37.209' )
rollback
SET autocommit=1
@Transactional(rollbackFor = {SQLException.class})
public void testCheckedExceptionRollback() throws SQLException {
testTransactionDao.addTestTransaction(build());
throw new SQLException("ggg");
}
嵌套方法(无异常)
--nest method 共插入2条记录 sql
SET autocommit=0
select @@session.tx_read_only
INSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:47:00.572' )
select @@session.tx_read_only
INSERT INTO test_transaction ( name,email,birth ) VALUES ( 'chenshun00','chenshun00@gmail.com','2019-05-04 14:47:00.635' )
commit
SET autocommit=1
@Transactional
public void testNestMethod() {
//insert
testTransactionDao.addTestTransaction(build());
this.subMethod();
}
private void subMethod() {
testTransactionDao.addTestTransaction(build());
}
嵌套方法带checked异常
--子方法出现运行运行时异常,回滚
SET autocommit=0
select @@session.tx_read_only
SELECT @@session.tx_isolation
INSERT 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' )
rollback
SET autocommit=1
@Transactional
public void testNestMethodRuntimeException() {
testTransactionDao.addTestTransaction(build());
this.subExceptionMethod();
}
private void subExceptionMethod() {
testTransactionDao.addTestTransaction(build());
throw new NullPointerException("运行时异常测试");
}
嵌套方法带unchecked异常.
set autocommit = 1
select @@session.tx_read_only
SELECT @@session.tx_isolation
set autocommit = 0
insert sql语句
insert sql语句
commit
set autocommit = 1
@Transactional
public void testNestMethodUncheckException() throws SQLException {
testTransactionDao.addTestTransaction(build());
this.subUncheckExceptionMethod();
}
private void subUncheckExceptionMethod() throws SQLException {
testTransactionDao.addTestTransaction(build());
throw new SQLException("运行时异常测试");
}
嵌套方法指定异常回滚
set autocommit = 1
select @@session.tx_read_only
SELECT @@session.tx_isolation
set autocommit = 0
insert sql语句
insert sql语句
rollback
set 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();
}
@Transactional
public 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
*/
@Transactional
public void firstTransaction() {
testTransactionDao.addTestTransaction(build());
this.secondTransaction();
}
/**
* 事务2
*/
@Transactional
public void secondTransaction() {
testTransactionDao.addTestTransaction(build());
}
总结
自己多试试,抓包看本质.