Spring编程式事务(手动创建事务)
文章目录
第一种方式 PlatformTransactionManager
@Test
public void test1() throws Exception {
//定义一个数据源
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/javacode2018?characterEncoding=UTF-8");
dataSource.setUsername("root");
dataSource.setPassword("root123");
dataSource.setInitialSize(5);
//定义一个JdbcTemplate,用来方便执行数据库增删改查
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//1.定义事务管理器,给其指定一个数据源(可以把事务管理器想象为一个人,这个人来负责事务的控制操作)
PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);
//2.定义事务属性:TransactionDefinition,TransactionDefinition可以用来配置事务的属性信息,比如事务隔离级别、事务超时时间、事务传播方式、是否是只读事务等等。
TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
//3.开启事务:调用platformTransactionManager.getTransaction开启事务操作,得到事务状态(TransactionStatus)对象
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
//4.执行业务操作,下面就执行2个插入操作
try {
System.out.println("before:" + jdbcTemplate.queryForList("SELECT * from t_user"));
jdbcTemplate.update("insert into t_user (name) values (?)", "test1-1");
jdbcTemplate.update("insert into t_user (name) values (?)", "test1-2");
//5.提交事务:platformTransactionManager.commit
platformTransactionManager.commit(transactionStatus);
} catch (Exception e) {
//6.回滚事务:platformTransactionManager.rollback
platformTransactionManager.rollback(transactionStatus);
}
System.out.println("after:" + jdbcTemplate.queryForList("SELECT * from t_user"));
}
步骤1:定义事务管理器PlatformTransactionManager
事务管理器相当于一个管理员,这个管理员就是用来帮你控制事务的,比如开启事务,提交事务,回滚事务等等。
spring中使用PlatformTransactionManager这个接口来表示事务管理器,
public interface PlatformTransactionManager {
//获取一个事务(开启事务)
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
//提交事务
void commit(TransactionStatus status) throws TransactionException;
//回滚事务
void rollback(TransactionStatus status) throws TransactionException;
}
步骤2:定义事务属性TransactionDefinition
定义事务属性,比如事务隔离级别、事务超时时间、事务传播方式、是否是只读事务等等。
spring中使用TransactionDefinition
接口来表示事务的定义信息,有个子类比较常用:DefaultTransactionDefinition
。
步骤3:开启事务
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
执行了getTransaction后,spring内部会执行一些操作,为了方便大家理解,咱们看看伪代码:
//有一个全局共享的threadLocal对象 resources
static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
//获取一个db的连接
DataSource datasource = platformTransactionManager.getDataSource();
Connection connection = datasource.getConnection();
//设置手动提交事务
connection.setAutoCommit(false);
Map<Object, Object> map = new HashMap<>();
map.put(datasource,connection);
resources.set(map);
从上面的代码就可以看出来 spring中的事务 datasource 和 con 是密切相关的
步骤4:执行业务操作
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
dataSource 因为这个datasource是和con密切相关的,所以使用jdbcTemplate
就是使用了事务
第二种方式TransactionTemplate
@Test
public void test1() throws Exception {
//定义一个数据源
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/javacode2018?characterEncoding=UTF-8");
dataSource.setUsername("root");
dataSource.setPassword("root123");
dataSource.setInitialSize(5);
//定义一个JdbcTemplate,用来方便执行数据库增删改查
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//1.定义事务管理器,给其指定一个数据源(可以把事务管理器想象为一个人,这个人来负责事务的控制操作)
PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);
//2.定义事务属性:TransactionDefinition,TransactionDefinition可以用来配置事务的属性信息,比如事务隔离级别、事务超时时间、事务传播方式、是否是只读事务等等。
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
transactionDefinition.setTimeout(10);//如:设置超时时间10s
//3.创建TransactionTemplate对象
TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager, transactionDefinition);
/**
* 4.通过TransactionTemplate提供的方法执行业务操作
* 主要有2个方法:
* (1).executeWithoutResult(Consumer<TransactionStatus> action):没有返回值的,需传递一个Consumer对象,在accept方法中做业务操作
* (2).<T> T execute(TransactionCallback<T> action):有返回值的,需要传递一个TransactionCallback对象,在doInTransaction方法中做业务操作
* 调用execute方法或者executeWithoutResult方法执行完毕之后,事务管理器会自动提交事务或者回滚事务。
* 那么什么时候事务会回滚,有2种方式:
* (1)transactionStatus.setRollbackOnly();将事务状态标注为回滚状态
* (2)execute方法或者executeWithoutResult方法内部抛出异常
* 什么时候事务会提交?
* 方法没有异常 && 未调用过transactionStatus.setRollbackOnly();
*/
transactionTemplate.executeWithoutResult(new Consumer<TransactionStatus>() {
@Override
public void accept(TransactionStatus transactionStatus) {
jdbcTemplate.update("insert into t_user (name) values (?)", "transactionTemplate-1");
jdbcTemplate.update("insert into t_user (name) values (?)", "transactionTemplate-2");
}
});
System.out.println("after:" + jdbcTemplate.queryForList("SELECT * from t_user"));
}
注意 ::什么时候事务会回滚,有2种方式
1) 方式1
在execute或者executeWithoutResult内部执行transactionStatus.setRollbackOnly();将事务状态标注为回滚状态,spring会自动让事务回滚
2)方式2
execute方法或者executeWithoutResult方法内部抛出任意异常即可回滚。