記憶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の錠に換えることができます。