1、對同一張表先insert再update是很快會引起死鎖的,不管操作的是否是同一記錄
解決方法:對于同一記錄,需要調整hibernate的映射策略,使得一次insert完成操作。對于不同的記錄需要在代碼中手動flush,使得update先于insert。
2、對兩張表進行多次update操作時,兩張表交替update也會很快引起死鎖
解決方法:在代碼中手動flush,保證對兩張表的update不會出現交替的情況。
3、部分大范圍掃描的select和update混合也會導致死鎖
解決方法:優化sql,盡量減少sql語句,通過給po增加持久化字段的方式減少關聯查詢
經過優化,大部分情況下數據庫死鎖的情況得以避免,另外奇怪的是通過事件探查器在死鎖時并未發現鎖升級的事件。但是在一些特殊情況下(例如多個并發匯聚的直接聯合),死鎖依舊發生。最后不得不對方法進行synchronized關鍵字同步,這個通過synchronized flush完成。業務方法不必同步,最后批量操作數據庫時進行同步。
換oracle進行測試,在未synchronized的情況下,未發生死鎖情況。由此可見sqlserver與oracle鎖實現機制存在很大的差別。對sqlserver鄙視之。另,同事說,sqlserver2005后性能和機制發生了很大的變化,未測試。
補充一下我的一個最簡單情況下的測試用例:
PO:
public class TestPO {
String id;
String name;
int num;
.
}
String id;
String name;
int num;

}
映射文件 hibernate3:
<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>
<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);
}
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);
}
TheadtestTemplate template = new TheadtestTemplate();
template.execute(new TheadtestCallback() {
public void doInThead(int suquence) {
// theadTestManager.testSave(suquence);
theadTestManager.testSaveByJdbc(suquence);
}
}, 10);
}
測試結果:不論是hibernate還是jdbc,并發情況下都很快就會引起sqlserver2000的死鎖,換用兩種數據庫驅動jtds和jturbo死鎖的情況沒有變化。
結論:sqlserver2000數據庫的lock配置策略,不支持,或者數據庫本身,就不支持對不同的行做同時操作(或者支持不完善),所謂的行鎖支持很不完善,死鎖情況非常容易發生。
補充:我對數據庫的一些實現機制也并不是很了解,所以這里也只能列出現象而不能解釋死鎖的根本原因。另外感謝Alex的討論。
http://www.aygfsteel.com/ronghao 榮浩原創,轉載請注明出處:)