订阅博客
收藏博客
微博分享
QQ空间分享

老人生日祝福语,敲了这么久的代码,@Transactional你真会用了吗,东方园林

频道:民生新闻 标签:聚宝币南沙 时间:2020年02月14日 浏览:132次 评论:0条

本章内容概要

  1. @Transactional注解失效问题的描述和复现
  2. @Transactional注解失效原痣的位置理讲解
  3. @Transactional注解失效的解决方案

问题描述

首先请大家看一下下老人生日祝福语,敲了这么久的代码,@Transactional你真会用了吗,东方园林面的代码,大家觉得有问题吗?代码的期望是子事务遇到异常进行回滚,而父事务不受其影响,在外部调用addParent()后,大家觉这段代码能做到吗?先卖个关子,请大家继续往下看哦,不看的话,就可能错过啥了哦。

@Service
@Slf4j
public class UserService {

@Autowired
private UserMapper userMapper;

@Transactional
//子事务回滚,不影响父事务
public void addParent(){
try{
addOperator阿穆隆入狱Record();
}catch (Exception e){
log.error("子事务出错了");
}
柏树User user = new User();
user.setName("parent");
user.setAge(50);
userMapper.in老人生日祝福语,敲了这么久的代码,@Transactional你真会用了吗,东方园林sert(user);
}

@Transactional(propagation 河北交管网= Propagation.REQUIRES_NEW)
pu需要人陪blic void addOperatorRecord(){
User user = new User();
user.setName("child");
user.setAge(28);
userMapper.insert(user);
throw n大众途安ew RuntimeException("child Transactional");
}

}

效果展示

输出日志

数据库现象

什么,上面的代码代码居然没有起作用,咋回事?那接下来就给大家带来原理分析,这个主要是女逼Spring的事务是实现依赖AOP,其最底层其实是JDK动态代理或cglib动态代理,就是在代理的方法中调用代理的方法,被动的另一方法会不起作用。下面给大家用JDK动态颠茄素代理来模拟一下现象

1.先声明个接口

public interface TransactionalInterface {
vo尹志平吮小龙女乳id createTransactional();
void commitTransactional();
}

2.正常的实现类

public 厉爵风class TestTransactionalImpl implements TransactionalInterface{信长之野望
@Override
public void createTransactional() {
System.out.println("===========createTransactional============");
commitTransactional();
}
@Override
public void commitTransactional() {
System.out.println("===========commitTransactional============");
}
}

3.代理的实现

public class ProxyTransactionalImpl implements InvocationHandler {
private TransactionalInterface target;
public ProxyTransactionalImpl(Tra香港海洋公园nsactionalInterface 老人生日祝福语,敲了这么久的代码,@Transactional你真会用了吗,东方园林target) {
this.target = target;
}
public TransactionalInte老人生日祝福语,敲了这么久的代码,@Transactional你真会用了吗,东方园林rface createProxy(){
return (Transac池城tionalInte卡戴珊家族rface)Proxy.newProxyInstance(ProxyTransactionalImpl.class.getClassLoader(),
new Class[] {Transactiona老人生日祝福语,敲了这么久的代码,@Transactional你真会用了吗,东方园林lInterface.class},
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[老人生日祝福语,敲了这么久的代码,@Transactional你真会用了吗,东方园林] args) throws Throwable {
if(method.getName().startsWith("c")虾怎么做好吃){
System.out.println("==============Proxy=================");
}
return method.invoke(target,args);
}
public static void main(String[] args){
TestTransactionalImpl testTransactional = new TestTransaction老人生日祝福语,敲了这么久的代码,@Transactional你真会用了吗,东方园林alImpl();
ProxyTransactionalImpl proxyTransactional = new ProxyTransactionalImpl(testTransactional);
TransactionalInterface proxy =proxyTransactional.createProxy();
proxy.createTransactional();
System.out.println("==============直接调用=============");
proxy.commitTransactional();
}
}

输出的现象

从图中可以看出代理典心类直接调用方法,代理是起作用的,如果在代理方法中调用代理方法,则是无效的

解决方案

注意数据库的类型要是InnoDB,Spring默认回滚的异常是RuntimeException,如果需要回滚Exception异常可以设置@Transactional(rollbackFor=Exception.class)来解决问题

1.使用xxxService.xxx()方法的形式,也是把被调用的方法重新移到一个类里

2.如果一定想在同一个类中调用的话,可以使用getBean方式来调用

try{
UserService userServic成熟男人头像e = (UserService) applicationContext.getBean("userService");
userSefurryrvice.addOperatorRecord();
}catch (Exception e){
log.err侠盗猎车手4or("子事务出错了");
}
User user = new User();
user.setName("parent");
user.setAge(50);
userMapper.insert(user);