MyBatis一级缓存引发的问题

发表于:MyBatis一级缓存引发的问题

一般的,我们在写一个系统的时候,都会分为持久层,服务层,和控制层,各层之间职责分明,对应的Entity,DTO,VO也是很明确知道用在哪里的,但是有时候为了方便,特别是用MyBatis的时候,直接从持久层返回一个vo,然后这个vo又作为方法的参数在系统之间来回调用,那么会引发什么样的问题呢?

假设我们有如下代码:

/**
 * 确认订单
 */
public boolean confirmOrder(String orderId){
    OrderVo orderVo = orderDao.findByOrderId(orderId);
    // 假设计算订单号需要用到一个特殊的利率
    BigDecimal annualRate = new BigDecimal(0.12);
    // 根据订单号和利率计算实际的价格
    String realAmount = calculateRealAmount(orderId, annualRate);
    System.out.println(orderVo.getAnnualRate.longValue());
}

/**
 * 计算订单实际价格的方法,传入orderVo和实际的利率,用于计算订单价格
 */
private BigDecimal calculateRealAmount(OrderVo orderVo, BigDecimal annualRate){
    OrderVo orderVo = orderDao.findByOrderId(orderId);
    orderVo.setAnnualRate(annualRate);  // 设置新的计算利率
    calculateRealAmount(orderVo);
}

/**
 * 计算订单实际价格的方法,传入orderVo用于计算
 */
private BigDecimal calculateRealAmount(OrderVo orderVo){
    return NumberUtils.mulBigDecimal(orderVo.getAmount, orderVo.getAnnualRate);
}

假设confirmOrder()是处于一个事务里面,confirmOrder()方法里面通过calculateRealAmount()方法计算了实际的订单金额,这两个方法都通过orderDao.findByOrderId(orderId);查找到了OrderVo,由于MyBatis默认开启了以及缓存,实际上这两个方法查找出来的是同一个OrderVo对象,所以calculateRealAmount()里面对orderVo的改动,也会影响到confirmOrder()里面的vo,所以confirmOrder(String orderId)最后一行输出的值也不是刚查找出来的了,使用不当,会造成潜在的bug。

下面就来总结一下这个问题。

代码规范问题引发脏数据

原因是MyBatis xml文件里面读取出来的是一个VO,某一些方法也使用该VO作为参数,在传递VO参数的时候,对VO进行了重新设置,导致接下来的地方读取vo的属性读到了脏数据。

项目规范:

分清各层数据的职责,防止出现类似情况;
Entity查找出来不要更改,更改后则一定要入库处理,也不要作为方法的参数进行传递;
禁止从数据库里面直接查找出VO。

mybatis一级缓存(session cache)引发的问题

【mybatis】多次查询缓存的问题

深入理解mybatis原理