2016-04-26 4 views
1

バネブック、スプリングデータ、およびmysqlを使用してトランザクションを理解しようとしています。バネデータとmysqlを使って2トランザクションメソッドを実行するとデッドロックが発生する

データベースのレコードを更新するために使用されるサービスUpdateServiceを作成しました。メソッドchangeとchange2はトランザクションで実行されます。

@Autowired 
private UserRepo userRepo; 

@Transactional(isolation = Isolation.SERIALIZABLE) 
public void change() { 
    User user = userRepo.findOne("Jan"); 

    write("before change", user); 
    sleep(2000); 
    user.setPassword("new password"); 
    write("after change", user); 
} 

@Transactional(isolation = Isolation.SERIALIZABLE) 
public void change2() { 
    User user = userRepo.findOne("Jan"); 

    write("before change2", user); 
    user.setSecondName("new name"); 
    write("after change2", user); 
} 

とするとき、私は私がログを受信した変更とCHANGE2メソッドを呼び出します。

before change User(name=Jan, secondName=Adam, password=Kowalski) 
before change2 User(name=Jan, secondName=Adam, password=Kowalski) 
after change2 User(name=Jan, secondName=new name, password=Kowalski) 
after change User(name=Jan, secondName=Adam, password=new password) 

その後も、私は例外が発生しました:

com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction 

取引CHANGE2は、変更前の始まり、なぜ私の質問があります終わらせる?デッドロックの理由は何ですか?

+0

文脈をもっと与えてください。すなわち、 'change'と' change2'はどのように実行されますか?それらは同時に実行されますか? –

+0

これらはコントローラの形で実行されます @RequestMapping( "/ change") private void change(){ updateService.change(); } change2は類似しています 私は郵便配達の変更と即座に変更2を実行します(これは2秒目に最初のトランザクションが終了するのを防ぐために2秒間スリープ状態を追加した理由です) – adrian215

+0

あなたのコードでは、 'change2'は' change'がトランザクションを終了した後にのみ開始します。 'findOne'メソッドは' SHARE MODE'でselectを実行します。これは同時読み込みを許可します。私が理解できないことはデッドロックです。 –

答えて

1

ベローは私の視点です:

変更前に開始しCHANGE2取引が行われている理由は? MySQLの

、まずあなたは、MySQL約バージョンを気にし、this official site url about transactionを参照してくださいする必要があります。特に、分離レベルの説明SERIALIZABLE

  • このレベルはREPEATABLE READ、のようですが、InnoDBは暗黙のうちにautocommitisが無効になっている場合SHAREモードで... LOCKを選択するために、すべてのプレーンなSELECTステートメントに変換します。自動コミットが(のCHANGE2読み出し動作をブロックしません、と言うことの変更読み出し動作)が有効になっている場合、SELECTは、独自のトランザクションです。したがって、読み取り専用であることが知られており、一貫性のある(非ロック)読み取りとして実行され、他のトランザクションをブロックする必要がない場合はシリアル化できます。 (自動コミットを無効にし、他のトランザクションが選択された行を変更した場合はブロックするようにSELECTプレーンを強制する。デッドロックの理由は何ですか?

    変更の操作を読んだとき

change2が実行されていると、同じ行に共有ロックを保持しているトランザクションが2つあります。の変更操作(トランザクションt1)とchange2(トランザクションt2)、t1はt2で待機し、は共有ロックを解放し、t2はt1がの共有ロックを解放するのを待つため、デッドロックが発生します。

http://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-model.html http://dev.mysql.com/doc/refman/5.7/en/innodb-lock-modes.html

希望はあなたを助けるために:私はお勧め

あなたは、MySQLのトランザクションとロック機構を参照してください。

+0

ありがとう、私は探していたJPAのソリューション私はそれがmysql設定であるとは思わなかった。 – adrian215

関連する問題