記憶synchronizedとRentrant Lockはspring事務で失効しました。


最近、あるプロジェクトのユーザーの流れる水とお金の金額が合併していることが分かりました。そして楽観的なロックを使ってこの問題を解決しました。しかし、決裁の任務があるので、同じ時刻に同じユーザーのお金が多く流れます。
  • StleObject Station,
  • Object Optimistic LockingFailure Exception,
  • CanotAcquire LockException
  • の異常を解決しましたが、やはりいいです。簡単な解ではなく、頭を働かせて、主要な業務ロジックを変えないで、どうやってパッチを適用しますか?一番簡単な方法は並行してシリアルに変えてデータベースで検索して修正した方法の外にsynchronizedのキーワードを入れましたが、その後並行して調べたデータは古いデータのsynchronizedが失効しました。次に、トランザクションが動的エージェントによって実現される明白な動的エージェントの方法であると考えられるが、synchronizedキーワード修飾はない。これは一例である。
    @Service
    class WalletApplicationSerive{
    
        @Transactional(rollbackFor =  Exception.class)
        public synchronized void pay(accountId, amount, outerCode){
           //          
        }
    }
    私たちが事務を使用すると、その背後の実装は、IOC容器に関連して動的エージェントが取得したWallettAppliation Seriveの例がすでにSpringによって変更されています(springがより複雑に実現されています。ここでは静的エージェントを例として説明するために、これは単なる例示です)
    
    class WalletApplicationSeriveProxy{
    
       private WalletApplicationSerivce tagert;
       
        public  void pay(accountId, amount, outerCode){
           tx.begin()
           try{
              tagert.pay(accountId, amount, outerCode)
           }catch(Exception e){
              tx.rollback()
              throw e;
           }
           tx.commit()
          
        }
    }
    ダイナミックエージェント:
       //     
        Object target ;
    
        Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), Main.class, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
               //   @Transcational          
               tx.begin();
               try{
                   method.invoke(target, args);
               }catch(Exception e){
                  tx.rollback();
                  throw e;
               }
               tx.commit();
               return null;
            }
            
        });
    すべてが簡単になりました。これはsynchronizedとRentrant Lockがspring事務で失効した原因です。どう解決しますか?簡単に代理店の外で事務を増やすことができます。
    @Service
    class WalletApplicationSerive{
    
        @Autowired
        InnerWalletApplicationSerive inner;
        
        public synchronized void pay(accountId, amount, outerCode){
           inner.pay(accountId, amount, outerCode)
        }
        
        @Service
        static class InnerWalletApplicationSerive{
            @Transactional(rollbackFor =  Exception.class)
            public void pay(accountId, amount, outerCode){
               //          
            }
        }
    }
    問題が解決されましたが、ここでロックされている粒度は太すぎます。ロックに対してより細かい粒度改造が可能です。
    @Service
    class WalletApplicationSerive{
    
        @Autowired
        InnerWalletApplicationSerive inner;
        
        public  void pay(accountId, amount, outerCode){
           synchronized(WalletLockManger.getLock(accountId)){
                inner.pay(accountId, amount, outerCode)
           }
          
        }
        
        @Service
        static class InnerWalletApplicationSerive{
            @Transactional(rollbackFor =  Exception.class)
            public void pay(accountId, amount, outerCode){
               //          
            }
        }
    }
    
    class WalletLockManger {
    
        private static final Map lockMap = new ConcurrentHashMap<>();
    
        public static String getLock(String accountId) {
            return lockMap.computeIfAbsent(accountId, Function.identity());
        }
    }
    synchronized(Wallet LockManger.get Lock)これには大きな改造空間があり、後に複数のインスタンスを配置する場合はここをredisの錠に換えることができます。