锁在事务中的错误使用

 

 锁在事务中的错误使用
 
 
 错误示例:
 

@Override
    @Transactional(rollbackFor = Exception.class)
    public Item add(ItemDTO dto) throws Exception {

        //锁商品,防并发
        String lockKey = StringUtil.format(Constants.LOCK_ACTIVITY_PRODUCT, dto.getItemId());
        //加锁
        boolean isLock = redisClient.trylock(lockKey, 2 * 60);
        AssertUtil.isTrue(isLock, "该商品正在被处理中,请稍后再试");
        try {
            Item item = itemMapper.selectByItemId(dto.getItemId());
           if(item==null){
            ...
            itemMapper.insert(newItem);
           }else{
            ...
            itemMapper.updateItem(item);
           }
           return item;
        } finally {
   //释放锁,此时事务还未提交
            redisClient.unlock(lockKey);
        }
    }


 
 事务的范围大于锁的范围,锁释放的瞬间可能事务还没来的及提交,看源码:
 

 protected Object invokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation)
   throws Throwable {

  // If the transaction attribute is null, the method is non-transactional.
  final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
  final PlatformTransactionManager tm = determineTransactionManager(txAttr);
  final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

  if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
   // Standard transaction demarcation with getTransaction and commit/rollback calls.
   TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
   Object retVal = null;
   try {
    // 执行完目标方法返回  (public Item add(ItemDTO dto) throws Exception)
    retVal = invocation.proceedWithInvocation();
   }
   catch (Throwable ex) {
    // target invocation exception
    completeTransactionAfterThrowing(txInfo, ex);
    throw ex;
   }
   finally {
    cleanupTransactionInfo(txInfo);
   }
   //提交事务
   commitTransactionAfterReturning(txInfo);
   return retVal;
  }

 

所以要保证线程安全锁应该加在事务之外

你可能感兴趣的:(分布式锁,事务,并发)