codingapi / springcloud-lcn-demo

LCN分布式事务框架v4.0 springcloud-lcn-demo
http://www.txlcn.org
220 stars 174 forks source link

事物控制在出现异常的时候只回滚了当前服务下面的,使用feign调用的远程服务没有被回滚掉 #7

Closed ouyang1203 closed 6 years ago

ouyang1203 commented 6 years ago

事物控制在出现异常的时候只回滚了当前服务下面的,使用feign调用的远程服务没有被回滚掉,初次接触这个框架,代码如下: package org.springcloud.order.service;

import org.springcloud.order.dao.OrderDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;

import com.codingapi.tx.annotation.ITxTransaction; import com.codingapi.tx.annotation.TxTransaction; @Service public class OrderService implements ITxTransaction{ @Autowired private OrderDao orderDao;

@Autowired
private ProductInterface productInterface;
/**
 * 插入订单系统数据
 * */
@TxTransaction(isStart=true)
@Transactional
public int save(String name,int amount){
    //FEIGN远程调用库存模块事物不会被这个RuntimeException回滚
    int b = productInterface.update(name, amount);
    //当前服务的事物回滚成功
    int a = orderDao.save(name, amount);
    if(true){
        throw new RuntimeException("aaaa");
    }
    return a+b;
}

} 库存模块的update方法如下: package org.springcloud.product.service;

import org.springcloud.product.dao.ProductDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;

import com.codingapi.tx.annotation.ITxTransaction; @Service public class ProductService implements ITxTransaction{ @Autowired private ProductDao productDao; @Transactional public int update(String name,int amount) { return productDao.update(name,amount); } } 配置都是按照官方案例进行配的呀,为何库存模块的事物无法回滚呢?

xlorne commented 6 years ago
  1. 可能本地事务没有开启。
  2. 可能是groupid没有正常传递参数。
ouyang1203 commented 6 years ago

针对tx-client源码分析后发现有如下方法因为我在项目里面没有设置数据源未运行,导致后续根据key获取task时taskMap为空 public TaskGroup createTask(String key,String type) { TaskGroup taskGroup = getTaskGroup(key); if(taskGroup==null){ taskGroup = new TaskGroup(); } taskGroup.setKey(key);

    String taskKey = type+"_"+key;

    TxTask task =  new TxTask(ConditionUtils.getInstance().createTask(taskKey));
    taskGroup.setCurrent(task);
    taskGroup.addTask(task);
    taskMap.put(key, taskGroup);
    return taskGroup;
}

在订单系统和库存系统中配置上数据源重启之后就正常能够回滚事物 @Autowired private Environment env;

@Bean
public DataSource dataSource(){
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setUrl(env.getProperty("spring.datasource.url"));
    dataSource.setUsername(env.getProperty("spring.datasource.username"));//用户名
    dataSource.setPassword(env.getProperty("spring.datasource.password"));//密码
    dataSource.setInitialSize(2);
    dataSource.setMaxActive(20);
    dataSource.setMinIdle(0);
    dataSource.setMaxWait(60000);
    dataSource.setValidationQuery("SELECT 1");
    dataSource.setTestOnBorrow(false);
    dataSource.setTestWhileIdle(true);
    dataSource.setPoolPreparedStatements(false);
    return dataSource;
} 

还是自己太过于想当然了,使用spring jdbc就觉得不用配置这个dataSource,导致TaskGroupManager的createTask方法不执行,后续根据key获取task时taskMap为空,获取不到对应的task下面的方法throw new ServiceException("update TxGroup error, groupId:" + txGroupId);就进不去 //已经进入过该模块的,不再执行此方法 if(!isHasIsGroup) { String type = txTransactionLocal.getType();

                TxTask waitTask = TaskGroupManager.getInstance().getTask(kid, type);

                //lcn 连接已经开始等待时.
                while (waitTask != null && !waitTask.isAwait()) {
                    TimeUnit.MILLISECONDS.sleep(1);
                }

                if (resTxGroup == null) {

                    //通知业务回滚事务
                    if (waitTask != null) {
                        //修改事务组状态异常
                        waitTask.setState(-1);
                        waitTask.signalTask();
                        throw new ServiceException("update TxGroup error, groupId:" + txGroupId);
                    }
                }
            }