Spring boot下的携程的DAL事务和回滚实现原理

首先申明,吐槽我程框架仅仅是希望框架能够更好,不代表不热爱公司哈。其次,携程的DAL框架(类似MyBatis的orm框架)确实有点那个不太给力了,估计和以前都是C#语言为主的历史原因。

DAL框架不给力的地方如下:

1、不支持Spring事务,很多功能没法实现,例如在事务性的a()里想要执行一段非事务的逻辑;或者在事务性的a()里想要执行一段新起事务的逻辑,但是b的事务和a的事务互不干扰。这些在Spring事务重视非常容易做到的,但是dal事务却无能为力。

2、注解必须加在方法上,不支持加上类头上,对于一个类下面有非常多的原子性操作方法的情况需要重复写若干遍相同注解代码。

3、使用时候出现问题,框架部门远程指点,结果给我引向了偏路了。。。-_-||

本文主要分析3的问题,正确使用方式如下!


import org.springframework.context.annotation.Configuration;
import com.ctrip.platform.dal.dao.annotation.EnableDalTransaction;
  
@Configuration
@EnableDalTransaction
public class TransactionConfig {}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TransactionConfig.class)
public class DataOperateServiceTest {

    @Autowired
    DataOperateServiceImpl<DataCreateEntity> service;
    
    @Test
    public void doUpdateTest() throws Exception{
        InitUpdateEntity updateData = new InitUpdateEntity();
        updateData.setDataId(229);
        updateData.setValue("init status edit 4000");
        service.doUpdateHandle(updateData, authentication);
    }
    
}
@Service
public class DataOperateServiceImpl<T> implements DataOperateService<T> {
    private static final Logger log = LoggerFactory.getLogger(DataOperateServiceImpl.class);
    
    /**
     * Create a new Data.
     *
     * @param data
     * @param authentication
     * @throws
     */
    @Override
    @DalTransactional(logicDbName = "xxxx")
    public TData doCreateHandle(DataCreateEntity data, Authentication authentication) throws SQLException,
            InvocationTargetException, IllegalAccessException, DataExistException {
        TData tData = new TData();
        DataCondition dataCondition = new DataCondition();
        BeanUtils.copyProperties(tData, data);
        tData.setVersion(1);
        tData.setStatus(StatusTransfer.initVisible());
        BeanUtils.copyProperties(dataCondition, data);
        dataCondition.setAppIds(Lists.newArrayList(data.getAppId()));
        if (CollectionUtils.isEmpty(DaoManager.queryData(dataCondition))) {
            tData = DaoManager.insert(Table.DATA, tData, authentication.getName());
        } else {
            log.error("The same data record has existed!");
            throw new DataExistException("The same data record has existed!");
        }
        if (DaoManager.queryData(dataCondition).size() != 1) {
            throw new DataExistException("The same data record has existed!");
        }
        return tData;
    }
}

或者上面第二个代码片段改为(更推荐):

@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration")
public class DataOperateServiceTest {

    @Autowired
    DataOperateServiceImpl<DataCreateEntity> service;
    
    @Test
    public void doUpdateTest() throws Exception{
        InitUpdateEntity updateData = new InitUpdateEntity();
        updateData.setDataId(229);
        updateData.setValue("init status edit 4000");
        service.doUpdateHandle(updateData, authentication);
    }
    
}

CGLB动态代码出业务的service类,然后DalTransactional实现CGLB的方法拦截,当发生异常或者执行sql等任何一个方法时候都会触发下面的代码:

DalClientFactory.getClient(getLogicDbName(method)).execute(new DalCommand() {
    
    @Override
    public boolean execute(DalClient client) throws SQLException {
        try {
            result.set(proxy.invokeSuper(obj, args));
        } catch (Throwable e) {
            throw DalException.wrap(e);
        }
        return false;
    }
}, hints);

然后会跳转到DalDirectClient类的execute方法,DalTransactionManager类中的doInTransaction方法如下

public <T> T doInTransaction(ConnectionAction<T> action, DalHints hints)throws SQLException{
	action.initLogEntry(connManager.getLogicDbName(), hints);
	action.start();

	Throwable ex = null;
	T result = null;
	int level;
	try {
		level = startTransaction(hints, action);
		action.populateDbMeta();

		result = action.execute();

		endTransaction(level);
	} catch (Throwable e) {
	    action.error(e);
		rollbackTransaction();
		MarkdownManager.detect(action.connHolder, action.start, e);
	}finally{
		action.cleanup();
	}

	action.end(result);

	return result;
}

当方法检测到throwable异常时候会执行 rollbackTransactional方法如下。

public void rollbackTransaction() throws SQLException {
	if(rolledBack)
		return;

	beforeRollback();
	rolledBack = true;
	// Even the rollback fails, we still set the flag to true;
	cleanup(false);
	afterRollback();
}

目前这个beforeRollback和afterRollback啥事也没干。cleanup实现其实和所有的orm框架做的事情是一样的,都是是否做Connection.commit()还是做Connection.rollback()。如果是回滚,则执行的是tomcat的DisposableConnectionFacade类的invoke方法去实现回滚,具体代码如下:

private void cleanup(boolean commit) {
	Connection conn = connHolder.getConn();
	try {
		if(commit)
			conn.commit();
		else
			conn.rollback();
	} catch (Throwable e) {
		logger.error("Can not commit or rollback on current connection", e);
	}

	try {
		conn.setAutoCommit(true);
	} catch (Throwable e) {
		e.printStackTrace();
	}
	
	connHolder.close();
	DalTransactionManager.clearCurrentTransaction();
}

原理主要就是上述的大致样子。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: biz dal 和 dao 是软件开发中常见的层级结构,用于将代码按照不同的功能和责任进行划分和组织。 biz(Business)层表示业务逻辑层,主要负责处理业务逻辑相关的操作和功能。在这一层中,开发人员会定义和实现业务实体、业务逻辑以及业务规则。biz层关注的是业务的具体实现细节,通过调用dal层提供的数据访问方法来操作数据库,完成业务逻辑的处理和计算,并将结果返回给上层。通过将业务逻辑与其他层进行分离,biz层使得系统的业务逻辑更加清晰和可维护。 dal(Data Access Layer)层表示数据访问层,主要负责与数据库进行交互,提供数据的增删改查功能。dal层是对数据库操作的封装,通过提供统一的接口和方法,使得上层可以方便地直接调用来访问和操作数据库中的数据。dal层封装了具体数据库的访问细节,包括连接数据库、执行SQL语句以及处理数据库事务等。通过将数据访问与业务逻辑分离,dal层使得数据库操作的代码重用性更高,同时也提高了系统的安全性和可扩展性。 dao(Data Access Object)即数据访问对象,是dal层的一种具体实现方式。dao对象主要负责封装对数据库的访问操作,提供CRUD(增删改查)等基本的数据库操作方法。dao层可以对数据库进行封装,屏蔽底层数据库的差异,使得上层业务模块可以以统一的方式访问不同类型的数据库。dao层还可以通过使用缓存技术等对数据库进行性能优化。通过使用dao对象,可以更好地组织和管理数据访问的代码,提高代码的重用性和可维护性。 总之,biz层、dal层和dao层都是软件开发中常用的层级结构,通过将不同的功能和责任进行分离和封装,可以提高代码的可维护性、可重用性和可扩展性。 ### 回答2: biz、dal和dao是一种常见的软件架构设计中的层级结构。它们代表了不同的职责和功能,用于实现系统的分层、解耦和易于维护。 biz层是业务逻辑层,主要负责实现系统的业务规则和业务流程。在这一层中,我们可以定义各种业务逻辑的处理,如数据处理、算法实现、工作流程控制等。biz层是整个系统的核心业务逻辑所在,其职责包括数据的处理、转换、验证等。它与用户的交互是通过控制层进行的,它们之间通过接口进行通信。 dal层是数据访问层,负责与数据库进行交互,实现数据的增删改查等基本操作。在dal层中,我们可以定义各种访问数据的方法,如连接数据库、执行SQL语句等。dal层的主要职责是封装数据库相关的操作,为biz层提供数据的存取能力。通常,dal层会处理数据的连接和事务管理,保证数据的一致性和完整性。 dao层是数据访问对象层,是在dal层基础上进一步抽象和封装的层次。在dao层中,我们可以定义数据对象的接口和实现,用于封装与数据库的交互细节。dao层的主要职责是提供简单、高效、易用的数据访问接口,为biz层提供数据的操作能力。通过dao层,biz层可以实现与各种不同类型的数据库(如关系型数据库、NoSQL数据库等)交互的透明性。 综上所述,biz、dal和dao的层级结构中,biz层为整个系统的业务逻辑层,dal层为数据访问层,dao层为数据访问对象层。它们之间明确了职责和功能,实现了系统的分层、解耦和易于维护。这种层级结构在项目开发中广泛应用,可以提高代码的可维护性和重用性,同时也方便了团队的协作和开发效率。 ### 回答3: Biz(业务逻辑层)和DAO(数据访问对象)是在软件开发中常用的两个层级,主要用于在应用程序中分离不同的职责和功能。它们之间的层级结构可以简单概括为: DAO层是在数据持久化方面负责与数据库进行交互的部分。它封装了与数据库相关的操作,提供了对数据的持久化和访问的方法。DAO层通常包含了数据的增删改查等基本操作,以及一些复杂的查询和事务处理。在DAO层的设计中,我们通常会使用一些持久化框架(如Hibernate、MyBatis等)来简化与数据库的交互。 Biz层是在业务逻辑方面负责处理具体的业务需求。它通过调用DAO层提供的数据访问方法,实现对数据的操作和处理。Biz层相当于对DAO层进行了一层封装,将数据访问的逻辑与业务逻辑进行了解耦,使得应用程序更加灵活和可维护。在Biz层的设计中,我们通常会对业务进行划分,并实现相应的业务功能方法。这些方法可以包含多个DAO层的数据访问操作,以完成具体业务逻辑的处理。 所以,biz和dao的层级结构一般是DAO层处于底层,负责与数据库进行数据的持久化和访问;而Biz层处于顶层,负责处理具体的业务逻辑需求,通过调用DAO层提供的数据访问方法,实现对数据的操作和处理。通过这种层级结构的划分,可以使应用程序的不同层级职责清晰分离,降低耦合度,提高代码的复用性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值