测试在sqlserver2000上进行,对工作流操作的相关方法在单元测试里进行多线程并发。测试发现sqlserver出现死锁的情况相当多,一些典
型的情况:
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:
class
TestPO {
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
>
被测试方法(都配置有事务):
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,并发情况下都很快就会引起sqlserver2000的死锁,换用两种数据库驱动jtds和
jturbo死锁的情况没有变化。
结论
:sqlserver2000数据库的lock配置策略,不支持,或者数据库本身,就不支持对不同的行做同时操作
(或者支持不完善),所谓的行锁支持很不完善,死锁情况非常容易发生。
补充:我对数据库的一些实现机制也并不是很了解,所以这里也只能列出现象而不能解释死锁的根本原因。另外感谢Alex的讨论。