| 事务事务主要有三种操作: 开始事务 start transaction提交事务 commit回滚事务 rollback
 Spring 中事务的实现Spring 中的事务操作分为两类: ?动操作事务。声明式?动提交事务.
 1.?动操作事务SpringBoot 内置了两个对象,DataSourceTransactionManager ?来获取事务(开启事务)、提交或 回滚事务的,
 ? TransactionDefinition 是事务的属性,在获取事务的时候需要将 TransactionDefinition 传递进去从?获得?个事务 TransactionStatus,实现代码如下:
 	@Autowired  
    DataSourceTransactionManager transactionManager;  
  
    @Autowired  
    TransactionDefinition definition;  
  
  
    @RequestMapping("/blogSubmit")  
    public String blogSubmit(String title, String content,@SessionAttribute(value = "user",required = false) User user)  {
	    
        TransactionStatus transactionStatus=transactionManager.getTransaction(definition);  
        Blog blog=new Blog();  
        blog.setTitle(title);  
        blog.setContent(content);  
        blog.setUserid(user.getUserId());  
        blog.setCategory("未定");  
        blogService.insert(blog);  
        transactionManager.rollback(transactionStatus);  
        return "redirect:/Blog_List.html";  
    }  
}
 2. Spring 声明式事务(?动事务)声明式事务的实现很简单,只需要在需要的?法上添加 @Transactional 注解就可以实现了,?需?动 开启事务和提交事务,进??法时?动开启事务,?法执?完会?动提交事务,如果中途发?了没有处理的异常会?动回滚事务,具体实现代码如下: @RequestMapping("/blogSubmit")  
@Transactional  
public String blogSubmit(String title, String content,@SessionAttribute(value = "user",required = false) User user)  {  
    Blog blog=new Blog();  
    blog.setTitle(title);  
    blog.setContent(content);  
    blog.setUserid(user.getUserId());  
    blog.setCategory("未定");  
    blogService.insert(blog);  
    return "redirect:/Blog_List.html";  
}
 当使用@Transactional修饰类的时候,如果执行的时候没有任何问题,就会自动的正常提交,如果执行的时候程序出现了异常,那么就会自动发生回滚. @RequestMapping("/blogSubmit")  
@Transactional  
public String blogSubmit(String title, String content,@SessionAttribute(value = "user",required = false) User user)  {  
    Blog blog=new Blog();  
    blog.setTitle(title);  
    blog.setContent(content);  
    blog.setUserid(user.getUserId());  
    blog.setCategory("未定");  
    blogService.insert(blog);  
    int a=10/0;  
    return "redirect:/Blog_List.html";  
}
 对于这种问题,程序的代码中出现了异常,所以这个插入博客的这个事务不会正常执行 所以,使用@transaction注解是非常的好用的,对于正常的没有错误的事务,正常提交;对于出现异常的事务,自动回滚. 同时,@transaction还提供了许多不同功能的参数:  value和transactionManager当有多个事务管理器的时候,我们可以使用该属性来选择哪一个事务管理器
 propagation 可以规定事务的传播机制,默认是Propagation.REQUIRED isolation 事务的隔离级别,默认是Isolation.DEFAULT
 Spring中事务的隔离级别一共有以下五种: public enum Isolation {  
    DEFAULT(-1),  
    READ_UNCOMMITTED(1),  
    READ_COMMITTED(2),  
    REPEATABLE_READ(4),  
    SERIALIZABLE(8);
}
 1. default 默认级别 指Spring的级别和对应的数据库种的级别一致
2. read uncommit 读不提交
3. read commit 读提交
4. repeatable commit 可重复读
5. Serialization 串行化
 @Transactional(isolation = Isolation.DEFAULT)
 timeout 设置隔离时间,如果超出时间的话,就回滚,默认是-1
 @Transactional(timeout = 1)
 readOnly 指定事务是只读的,默认值是false,如果开启为true,表示这个事务只允许读,不可以修改.
 这样可以避免加锁解锁的时间消耗  rollbackFor和rollbackForClassName 抛出异常的类型,回滚事务 noRollbackFor和noRollbackForClassName 抛出异常的类型,不回滚事务
 但是这个@Transaction注解还有一个例外,那就是被捕获的异常不会回滚,因为它任务这个异常已经被解决掉了,所以不需要回滚了,是安全的 @RequestMapping("/blogSubmit")  
@Transactional  
public String blogSubmit(String title, String content,@SessionAttribute(value = "user",required = false) User user)  {  
    Blog blog=new Blog();  
    blog.setTitle(title);  
    blog.setContent(content);  
    blog.setUserid(user.getUserId());  
    blog.setCategory("未定");  
    blogService.insert(blog);  
    try {  
        int a=10/0;  
    }catch (Exception e){  
  
    }  
    return "redirect:/Blog_List.html";  
}
 对异常进行try catch之后,就不会回滚了 如何让被捕获的异常也回滚呢?有以下两种方法: 再throw出去
 try {  
    int a=10/0;  
}catch (Exception e){  
    throw e;  
}
 使用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()函数
 try {  
    int a=10/0;  
}catch (Exception e){  
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();  
}
 @Transaction的原理@Transactional 是基于 AOP 实现的,AOP ?是使?动态代理实现的。如果?标对象实现了接?, @Transactional 在开始执?业务之前,通过代理先开启事务,在执?成功之后再提交事务。如果中途遇 到的异常,则回滚事务。 Spring的事务传播机制Spring 事务传播机制定义了多个包含了事务的?法,相互调?时,事务是如何在这些?法间进?传递 的。 事务传播机制和事务隔离机制的区别是什么?  
 事务隔离级别是保证多个并发事务执?的可控性的(稳定性的),?事务传播机制是保证?个事务在多个调??法间的可控性的(稳定性的)。
 种类Spring 事务传播机制包含以下 7 种: Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加?该事务;如果当前没有事务,则创建?个新的事务Propagation.SUPPORTS:如果当前存在事务,则加?该事务;如果当前没有事务,则以?事务的 ?式继续运?。Propagation.MANDATORY:(mandatory:强制性)如果当前存在事务,则加?该事务;如果当 前没有事务,则抛出异常。Propagation.REQUIRES_NEW:表示创建?个新的事务,如果当前存在事务,则把当前事务挂 起。也就是说不管外部?法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部?法会新开 启??的事务,且开启的事务相互独?,互不?扰。Propagation.NOT_SUPPORTED:以?事务?式运?,如果当前存在事务,则把当前事务挂起。Propagation.NEVER:以?事务?式运?,如果当前存在事务,则抛出异常。Propagation.NESTED:如果当前存在事务,则创建?个事务作为当前事务的嵌套事务来运?;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED
 
 具体演示下面以一个例子来观察再不同的传播机制下,事务之间的影响是什么样子的. 以下代码实现中,先开启事务先成功插??条?户数据,然后再执??志报错,?在?志报错是发?了 异常: UserController: 	@RestController 
	public class UserController { 
	   @Resource    
	   private UserService userService;    
	   @Resource    
	   private LogService logService;    
	   @RequestMapping("/save")    
	   @Transactional(propagation = Propagation.REQUIRED)    
	   public Boolean save(User user) {        
		   userService.save(user);           
		   logService.saveLog("?户插?:" + user.getName());
			return true;
		}
	}
 UserService: @Service 
public class UserService {    
	@Resource    
	private UserMapper userMapper;     
    @Transactional(propagation = Propagation.REQUIRED)     
	public int save(User user) {         
         System.out.println("执? save ?法.");        
         return userMapper.save(user);   
    }
}
 logService: @Service 
public class LogService {    
	@Resource    
	private LogMapper LogMapper;     
    @Transactional(propagation = Propagation.REQUIRED)     
	public int save(Log log) {         
         System.out.println("执? save ?法.");        
         return LogMapper.save(log);   
    }
}
 当传播机制的类型是REQUIRED的时候,表示后来的事务都加入原来的事务.所以,当日志发送异常回滚之后,因为它们已经成一体了,所以用户插入也会失败,也会回滚当传播机制的类型是REQUIRED_NEW的时候,因为这个不使用当前事务,而是新创建一个事务,所以日志事务和用户事务都是相互独立的.日志事务发生回滚不会影响用户事务的正常提交当传播机制的类型是NESTY的时候,也就是嵌套机制时,当日志发送错误的时候,也只是回滚日志,用户事务正常执行.这是因为嵌套机制在嵌套的时候会有一个连接点,每次回滚之后都会回到相应的连接点,不会全部回滚当传播机制的类型是NOT_SUPPORTED的时候,也就是不支持事务的类型.就算是日志出现了异常,但是因为不是以事务的机制运行的,所以就会正常的提交,不会发生回滚
 |