简单的sql操作---TrancationTest
@Component
public class TrancationTest {
Logger logger = LoggerFactory.getLogger(TrancationTest.class);
private UserService userService;
public TrancationTest(UserService userService){
this.userService = userService;
}
@Transactional(rollbackFor = Exception.class)
public void TrancationLog() {
User user = userService.getUserByUserAccountOrName("sqc");
logger.info("Transaction 开始执行");
logger.info("the detail information of user",user);
try{
user.setUsername("sqc1");
userService.updateById(user);
logger.info("步骤1 the detail information of user",user.toString());
user.setMail("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
userService.updateById(user);
logger.info("步骤2 the detail information of user",user.toString());
}catch (Exception e){
logger.info("异常");
throw new RuntimeException();//和下面二选一
// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
}
测试类------DemoLoginApplicationTests
@Test
public void testTranaction() throws Exception {
TrancationTest trancationTest = new TrancationTest(userService);
trancationTest.TrancationLog();
}
TrancationLog中包含着两个操作 一个是简单的修改username不报错 第二个是修改mail邮箱使修改后的邮箱长度超出数据库限制报错
遇到的问题是:
在外层引用时并没有在测试方法前加Transcation注解 按照事务的传播机制 应该是外部没有事务 运行到trancationTest对象的TrancationLog()方法时 开始新事务 然后走到修改mail报错的部分进行回滚 把之前的修改username的操作一块回滚掉
但是实际并没有 数据库中的username被成功修改了 而且mail的修改因异常中断.
问了大佬之后,大佬的回答是"spring容器在实例化bean的时候会对每个bean自动生成一个代理类,对加了@Transactional注解的会走代理才会回滚,你自己new的没有对应的代理类"
也就是说我自己在 TrancationTest trancationTest = new TrancationTest(userService); 是没有spring管理的实例化过程的,所以也不会有相应的代理类来感知到事务注解 因此才不能回滚.
所以只要改成
package com.best800.demologin.service;
import com.best800.demologin.model.DTO.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
/**
* @ClassName ${Name}
* @Description TODO
* @Author < a href="jcsong50@best-inc.com">sqc</a>
* @Date 2019/4/8 16:13
* @Version 1.0
*/
@Component
public class TrancationTest {
Logger logger = LoggerFactory.getLogger(TrancationTest.class);
@Autowired
UserService userService;
@Transactional(rollbackFor = Exception.class)
public void TrancationLog() {
User user = userService.getUserByUserAccountOrName("sqc");
logger.info("Transaction 开始执行");
logger.info("the detail information of user",user);
try{
user.setUsername("sqc1");
userService.updateById(user);
logger.info("步骤1 the detail information of user",user.toString());
user.setMail("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
userService.updateById(user);
logger.info("步骤2 the detail information of user",user.toString());
}catch (Exception e){
logger.info("异常");
// throw new RuntimeException();//和下面二选一
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
}
和
@Autowired
TrancationTest trancationTest;
@Test
public void testTranaction() throws Exception {
trancationTest.TrancationLog();
}
轻松搞定.
还有一个遇到的错误一并写出
@Autowired
static UserService userSerivce;
收获了一波nullPointException
静态变量、类变量不是对象的属性,而是一个类的属性,所以静态方法是属于类(class)的,普通方法才是属于实体对象(也就是New出来的对象)的,spring注入是在容器中实例化对象,所以不能使用静态方法。
而使用静态变量、类变量扩大了静态方法的使用范围。静态方法在spring是不推荐使用的,依赖注入的主要目的,是让容器去产生一个对象的实例,然后在整个生命周期中使用他们,同时也让testing工作更加容易。
一旦你使用静态方法,就不再需要去产生这个类的实例,这会让testing变得更加困难,同时你也不能为一个给定的类,依靠注入方式去产生多个具有不同的依赖环境的实例,这种static field是隐含共享的,并且是一种global全局状态,spring同样不推荐这样去做。
---------------------
作者:_Jason_PC_
来源:优快云
原文:https://blog.youkuaiyun.com/u013675978/article/details/82967202
版权声明:本文为博主原创文章,转载请附上博文链接!