package study.demo.controller;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import study.demo.exception.MyException;
import javax.annotation.PostConstruct;
/**
* @author :xcz 2020/7/1 11:32
* 天靈靈地靈靈,代碼不要有問題
*
* spring 事务失效
*
*
*/
@Service
public class TransactionService {
/**
* 1.在异常被自己捕获并且没有重新抛出的情况下会造成事务失效
* 2.如果抛出的是自定义的检查性Exception的话也是会导致事务失效的,spring的事务只会对Error与RuntimeException及其子类这些异常,做出回滚
* 2.1 rollbackFor属性 指定我们的自定义异常
* 2.2 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 进行手动回滚
* 3. 如果是进行自调用,就会导致失效(即一个类中A方法调用B方法,B方法是有事务注解的)
* 3.1 通过@Autowired 注入自身的aop代理对象,调用代理对象的事务方法,即可开启事务
* 3.2 将当前类代理对象暴露到当前线程的局部变量中,进而调用代理对象的方法
* 3.3 在外部开启事务,这样内部的事务就会包含在外部的事务中
* 4. 如果spring定义的隔离级别和数据库的不一样,则以spring定义的为准。另外,如果spring设置的隔离级别数据库不支持,效果取决于数据库。
* 5. spring事务控制放在service层,在service方法中一个方法调用service中的另一个方法,默认只开启一个事务,因为spring事务传播机制默认是将当前事务加到上一个事务上
* 6. 怎么保证spring事务内的连接唯一性?因为那个Connection在事务开始时封装在了ThreadLocal里,后面事务执行过程中,都是从ThreadLocal中取的,肯定能保证唯一,因为都是在一个线程中执行的!
* 7.自定义事务管理器
* @Bean("myManager")
* public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource){
* return new DataSourceTransactionManager(dataSource);
* }
*/
private JdbcTemplate jdbcTemplate;
public TransactionService(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
@Transactional(value = "myManager")
public String transaction(){
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(1,'20190090', 2000, '测试')");
return "true";
}
// 1.在异常被自己捕获并且没有重新抛出的情况下会造成事务失效
/*@Transactional
public String transaction(){
try {
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(1,'20190090', 2000, '测试')");
}catch (Exception e){
e.printStackTrace();
}
return "true";
}*/
// 2.如果抛出的是自定义的Exception的话也是会导致事务失效的,spring的事务只会对Error与RuntimeException及其子类这些异常,做出回滚
/*@Transactional
public String transaction() throws MyException{
try {
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(1,'20190090', 2000, '测试')");
}catch (Exception e){
e.printStackTrace();
throw new MyException();
}
return "true";
}*/
// 2.1指定我们的自定义异常
/*@Transactional(rollbackFor = MyException.class)
public String transaction() throws MyException{
try {
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(1,'20190090', 2000, '测试')");
}catch (Exception e){
e.printStackTrace();
throw new MyException();
}
return "true";
}*/
// 2.2TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 进行手动回滚
/*@Transactional()
public String transaction(){
//jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
System.out.println("手动回滚!");
return "true";
}*/
// 3. 如果是进行自调用,就会导致失效
/*public String transaction(){
return transaction2();
}
@Transactional()
public String transaction2(){
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(1,'20190090', 2000, '测试')");
return "true";
}*/
// 3.1 通过@Autowired 注入自身的aop代理对象,调用代理对象的事务方法,即可开启事务
/* @Autowired
private TransactionService transactionService;
public String transaction(){
return transactionService.transaction2();
}
@Transactional()
public String transaction2(){
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(1,'20190090', 2000, '测试')");
return "true";
}*/
// 3.2 将当前类代理对象暴露到当前线程的局部变量中,进而调用代理对象的方法
/*public String transaction(){
TransactionService transactionService = (TransactionService) AopContext.currentProxy();
return transactionService.transaction2();
}
@Transactional
public String transaction2(){
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(1,'20190090', 2000, '测试')");
return "true";
}*/
// 在外部开启事务,这样内部的事务就会包含在外部的事务中
/*@Transactional()
public String transaction(){
return transaction2();
}
@Transactional()
public String transaction2(){
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(2,'20190090', 2000, '测试')");
jdbcTemplate.update("insert into sp_principle(id,sno,department_id,position) values(1,'20190090', 2000, '测试')");
return "true";
}*/
}