高同時テストでのいくつかの問題と解決
テストはsqlserver 2000で行い、ワークフロー操作に関する方法はユニットテストでマルチスレッド同時実行を行う.テストでは、sqlserverにデッドロックが発生することが多く、典型的な場合があります.
1、同じテーブルに対してまずinsertしてからupdateを行うと、操作が同じレコードであるかどうかにかかわらず、すぐにデッドロックを引き起こす.
解決方法:同じレコードに対してhibernateのマッピングポリシーを調整し、insertが操作を完了するようにする必要があります.異なるレコードについては、updateがinsertより先になるようにコード内で手動flushが必要です.
2、2枚のテーブルを複数回update操作すると、2枚のテーブルが交互にupdateをしてもすぐにデッドロックを引き起こす
解決方法:コード内で手動flushを行い、2つのテーブルのupdateが交互に表示されないことを保証します.
3、一部の広範囲スキャンのselectとupdateの混合もデッドロックを引き起こす
解決方法:sqlを最適化し、できるだけsql文を減らし、poに永続化フィールドを増やすことで関連クエリーを減らす
最適化により、ほとんどの場合、データベースのデッドロックは回避されます.また、イベントプローブによってデッドロック時にロックがアップグレードされたイベントは見つかりません.しかし、いくつかの特殊な場合(例えば、複数の同時集約の直接結合)、デッドロックは依然として発生する.最後に、synchronized flushによって完了するsynchronizedキーワード同期を行う必要があります.ビジネス・メソッドは同期する必要はありません.最後にデータベースを一括操作したときに同期します.
oracleを交換してテストを行い、synchronizedがない場合、生死ロックが発生していない場合.このことから,sqlserverとoracleロックの実現メカニズムには大きな違いがあることが分かる.また、同僚によると、sqlserver 2005後、性能とメカニズムが大きく変化し、テストされていないという.
私の最も簡単な状況でのテスト例を補足します:PO:
http://www.blogjava.net/ronghao栄浩オリジナル、転載は出典を明記してください:)
1、同じテーブルに対してまずinsertしてからupdateを行うと、操作が同じレコードであるかどうかにかかわらず、すぐにデッドロックを引き起こす.
解決方法:同じレコードに対してhibernateのマッピングポリシーを調整し、insertが操作を完了するようにする必要があります.異なるレコードについては、updateがinsertより先になるようにコード内で手動flushが必要です.
2、2枚のテーブルを複数回update操作すると、2枚のテーブルが交互にupdateをしてもすぐにデッドロックを引き起こす
解決方法:コード内で手動flushを行い、2つのテーブルのupdateが交互に表示されないことを保証します.
3、一部の広範囲スキャンのselectとupdateの混合もデッドロックを引き起こす
解決方法:sqlを最適化し、できるだけsql文を減らし、poに永続化フィールドを増やすことで関連クエリーを減らす
最適化により、ほとんどの場合、データベースのデッドロックは回避されます.また、イベントプローブによってデッドロック時にロックがアップグレードされたイベントは見つかりません.しかし、いくつかの特殊な場合(例えば、複数の同時集約の直接結合)、デッドロックは依然として発生する.最後に、synchronized flushによって完了するsynchronizedキーワード同期を行う必要があります.ビジネス・メソッドは同期する必要はありません.最後にデータベースを一括操作したときに同期します.
oracleを交換してテストを行い、synchronizedがない場合、生死ロックが発生していない場合.このことから,sqlserverとoracleロックの実現メカニズムには大きな違いがあることが分かる.また、同僚によると、sqlserver 2005後、性能とメカニズムが大きく変化し、テストされていないという.
私の最も簡単な状況でのテスト例を補足します:PO:
public class TestPO {
String id;
String name;
int num;
....
}
マッピングファイルhibernate 3:<hibernate-mapping default-access="field">
<class table="WFMS_TESTPO" name="com.eway.workflow.test.po.TestPO">
<id name="id" column="ID"><generator class="uuid" /></id>
<property name="name" column="NAME" type="string"/>
<property name="num" column="NUM" type="integer"/>
</class>
</hibernate-mapping>
テストメソッド(トランザクションが構成されています): public void testSave(int num) {
TestPO po = new TestPO();
po.setName("ronghao");
po.setNum(num);
theadTestDao.save(po);
po.setName("haorong");
}
public void testSaveByJdbc(int num) {
String sql = "insert into WFMS_TESTPO (ID,NAME,NUM) values (?,'RONGHAO',?)";
Object[] params = new Object[]{num,num};
jdbcTemplate.update(sql, params);
sql="update WFMS_TESTPO set name='haorong' where id=?" ;
params = new Object[]{num};
jdbcTemplate.update(sql, params);
}
試験例: public void testSave() throws Exception {
TheadtestTemplate template = new TheadtestTemplate();
template.execute(new TheadtestCallback() {
public void doInThead(int suquence) {
// theadTestManager.testSave(suquence);
theadTestManager.testSaveByJdbc(suquence);
}
}, 10);
}
テスト結果:hibernateでもjdbcでも、同時にsqlserver 2000のデッドロックがすぐに発生し、2つのデータベースでjtdsとjturboデッドロックを駆動する場合は変化しません.結論:sqlserver 2000データベースのlock構成ポリシーは、サポートされていないか、データベース自体が、異なるローに対して同時操作(またはサポートが不完全)をサポートしていないか、いわゆるローロックサポートが不完全で、デッドロック状況が非常に発生しやすい.補足:私はデータベースのいくつかの実装メカニズムについてもよく知らないので、デッドロックの根本的な原因を説明することはできません.http://www.blogjava.net/ronghao栄浩オリジナル、転載は出典を明記してください:)