高并发测试下的一些问题及解决

测试在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锁实现机制存在很大的差别。另,同事说,sqlserver2005后性能和机制发生了很大的变化,未测试。

补充一下我的一个最简单情况下的测试用例: PO:

view plain copy to clipboard print ?
  1. public class TestPO {  
  2.   
  3.     String id;  
  4.   
  5.     String name;  
  6.   
  7.     int num;  
  8.   
  9.      
  10.   
  11.     ....  
  12.   
  13. }  
映射文件 hibernate3:
view plain copy to clipboard print ?
  1. <hibernate-mapping default-access="field">  
  2.   
  3.   <class table="WFMS_TESTPO" name="com.eway.workflow.test.po.TestPO">  
  4.   
  5.   
  6.   
  7.     <id name="id" column="ID"><generator class="uuid" /></id>  
  8.   
  9.   
  10.   
  11.     <property name="name" column="NAME" type="string"/>  
  12.   
  13.   
  14.   
  15.     <property name="num" column="NUM" type="integer"/>  
  16.   
  17.   
  18.   
  19.   </class>  
  20.   
  21. </hibernate-mapping>  
被测试方法(都配置有事务):
view plain copy to clipboard print ?
  1. public void testSave(int num) {  
  2.   
  3.     TestPO po = new TestPO();  
  4.   
  5.     po.setName("ronghao");  
  6.   
  7.     po.setNum(num);  
  8.   
  9.     theadTestDao.save(po);  
  10.   
  11.     po.setName("haorong");  
  12.   
  13. }  
  14.   
  15.   
  16.   
  17. public void testSaveByJdbc(int num) {  
  18.   
  19.     String sql = "insert into WFMS_TESTPO (ID,NAME,NUM) values (?,'RONGHAO',?)";  
  20.   
  21.     Object[] params = new Object[]{num,num};  
  22.   
  23.     jdbcTemplate.update(sql, params);  
  24.   
  25.     sql="update WFMS_TESTPO set name='haorong' where id=?"  ;  
  26.   
  27.     params = new Object[]{num};  
  28.   
  29.     jdbcTemplate.update(sql, params);  
  30.   
  31. }  
测试用例:
view plain copy to clipboard print ?
  1.      public void testSave() throws Exception {  
  2.   
  3.         TheadtestTemplate template = new TheadtestTemplate();  
  4.   
  5.         template.execute(new TheadtestCallback() {  
  6.   
  7.             public void doInThead(int suquence) {  
  8.   
  9. //               theadTestManager.testSave(suquence);  
  10.   
  11.                 theadTestManager.testSaveByJdbc(suquence);  
  12.   
  13.             }  
  14.   
  15.         }, 10);  
  16.   
  17.     }  
测试结果:不论是hibernate还是jdbc,并发情况下都很快就会引起sqlserver2000的死锁,换用两种数据库驱动jtds和jturbo死锁的情况没有变化。 结论:sqlserver2000数据库的lock配置策略,不支持,或者数据库本身,就不支持对不同的行做同时操作(或者支持不完善),所谓的行锁支持很不完善,死锁情况非常容易发生。 补充:我对数据库的一些实现机制也并不是很了解,所以这里也只能列出现象而不能解释死锁的根本原因。

http://www.blogjava.net/ronghao 荣浩原创,转载请注明出处:) 

你可能感兴趣的:(sql,Hibernate,数据库,测试,insert,sqlserver)