posts - 193,  comments - 520,  trackbacks - 0
          測試在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:
          public 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的討論。


          http://www.aygfsteel.com/ronghao 榮浩原創,轉載請注明出處:)
          posted on 2008-06-19 13:34 ronghao 閱讀(6270) 評論(22)  編輯  收藏 所屬分類: 工作日志

          FeedBack:
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-19 15:02 | Alex
          xd ,你配置了事務了嘛?  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決
          2008-06-19 17:55 | flybean
          1、死鎖,還是鎖阻塞,這是個問題。
          2、悲觀并發、樂觀并發生來以久,各有優缺點,搞清楚再來鄙視。  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 09:14 | Alex
          1、對同一張表先insert再update是很快會引起死鎖的,不管操作的是否是同一記錄
          2、對兩張表進行多次update操作時,兩張表交替update也會很快引起死鎖
          3、部分大范圍掃描的select和update混合也會導致死鎖

          如果連這些問題都解決不了,你覺得是數據庫問題,還是你的問題呢?

          別拿那么多名詞出來嚇人,這個招數我上小學的時候用來嚇唬老師的,現在已經不用了。

          就撿最后一個說吧,樂觀鎖,如果你控制不了,還是就不要用了,您還就是老老實實的本分點,使用數據庫本地提供的鎖功能吧,犧牲點數據庫的性能,也總比你數據更新失敗要好,如果你非要使用hibernate的樂觀鎖,請控制好,內存中的數據和數據庫中的數據一致性。  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 09:28 | ronghao
          @Alex
          我想你并沒有弄明白問題的關鍵。樂觀鎖和悲觀鎖的作用是防止多個事務對同一數據操作產生沖突的兩種策略。而我的問題是多個線程(即多個事務)并發操作不同的數據。不知道明不明白意思。
          ps:以前我也把這兩者的概念經常混淆。
            回復  更多評論
            
          # re: 高并發測試下的一些問題及解決
          2008-06-20 09:29 | BeanSoft
          說不定是濫用 Hibernate 導致的后果  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 09:34 | ronghao
          @BeanSoft
          我倒真的認為是數據庫的原因。
          一個簡單的例子:很簡單的po:
          String id;
          String name;
          兩個字段,執行操作:
          TestPO po=new TestPO();
          po.setName("ronghao");
          dao.save(po);
          dao.flush();
          po.setName("haorong");
          配置事務,單元測試兩個線程并發,sqlserver2000下馬上死鎖。  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 09:39 | ronghao
          @BeanSoft
          當然,我并沒有用jdbc直接測試  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:12 | Alex
          @ronghao
          如果不是多線程,那么配置事務還有何用,如果所有操作都在同一個流水線上,那么配置事務不是浪費人民的感情嘛?

            回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:18 | Alex
          使用hibernate樂觀鎖 如果導致你保存失敗,簡單點說,就是你的兩個線程或者多個線程所控制的內存中的數據和數據庫中數據集已經不一致了。

          如果使用悲觀鎖,導致你保存失敗,那么說明你事務配置的問題,或者至少說明你測試用例的事務配置有問題,要不你直接試試 jdbc 并且硬編碼事務看看。

          否則 sqlserver2000 真的不要玩了,兩個線程都是死鎖。。。

            回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:20 | Alex
          同時操作同的記錄集合,一方面要看你數據庫使用什么lock策略,一方面還要看你代碼的控制。  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:21 | Alex
          同時操作不同的記錄集合,一方面要看你數據庫使用什么lock策略,一方面還要看你代碼的控制.  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:21 | ronghao
          @Alex
          你的說法沒有錯。我想問題的原因在于死鎖的原因你我的理解有差異。
          你理解的是對數據庫表同一記錄并發操作引起數據庫死鎖,這個顯然是應用程序應該控制和避免的。
          而我的意思是并發操作某一動作,例如同時啟動100個工作流流程,這個盡管操作的是同一張表但是顯然是針對不同的記錄,此時,樂觀鎖、悲觀鎖都是沒有意義的。
          當然,我對數據庫的一些實現機制也并不是很了解,所以這里也只能列出現象而不能解釋死鎖的根本原因。  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:26 | ronghao
          @Alex
          補充說明一下,在我的測試中,不會出現兩個線程互相修改沖突的情況,甚至select也不會沖突,因為流程實例ID一開始就將所有的數據區分開來。我是并發啟動多個流程,然后并發提交這些流程。  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:31 | Alex
          上面我也說了,如果你直接使用hibernate的樂觀鎖,那么最細粒度的數據其實是由你自己來控制的,只要保持內存中的當前的數據在需要保存時和數據庫中的保存相同的version 就可以了,然后不管 有多少個線程insert 或者 update ,只要每個線程都滿足這個要求,就能保存成功了,當然,如果你的數據庫的lock配置策略,不支持,或者數據庫本身,就不支持對不同的行做同時操作(或者支持不完善),所謂的行鎖,那么肯定會像你所說的那樣發生死鎖。
            回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:37 | Alex
          @ronghao
          如果每個線程只處理 某一個或一些獨立 流程id相關的數據,而沒有交叉數據,那么還會出現這種現象。

          1.使用jdbc做這種測試,排除是否是hibernate的使用或者hibernate本身對2000支持的問題問題。(jdbc驅動也很關鍵。)
          2.查閱sql2000 對行鎖的支持程度。
            回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:45 | ronghao
          @Alex
          哈哈,正如你說的,我想問題在這里:
          當然,如果你的數據庫的lock配置策略,不支持,或者數據庫本身,就不支持對不同的行做同時操作(或者支持不完善),所謂的行鎖,那么肯定會像你所說的那樣發生死鎖。
          這也是我想表達的。我想有時間應該請個專業的DBA來,我也查過了SQLSERVER的鎖機制,但是具體到這里理解還是存在問題。
          另外你對樂觀鎖的理解也很到位。如果是多個事務同時提交一個流程,樂觀鎖就會起作用。
            回復  更多評論
            
          # re: 高并發測試下的一些問題及解決[未登錄]
          2008-06-20 10:46 | ronghao
          @Alex
          好的,謝謝你的意見。我會用jdbc做這個測試。  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決
          2008-06-20 16:30 | BeanSoft
          是呀 JDBC 先測試下比較好 排除法 如果 JDBC 也不行 那八九成是 SQL Server 問題 坊間的傳言都認為 SQL Server 好多地方不如 Oracle  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決
          2008-06-21 19:45 | 鬼狗
          pk的這么熱烈丫, 我想可能先要搞清楚的是行鎖,頁鎖和表鎖這些基本概念,搞清楚不同數據庫的鎖機制,然后再來談樂觀鎖還是悲觀鎖會比較容易理解。

          我估計樓主缺少在sybase,db2下的工作經驗, 所以才會這么激動。不同數據庫的設計本身是有相當大差異的,很難說好壞,我印象中,缺省情況下對鎖的處理比較不傷腦筋的就是oracle了,其他的不管是sybase還是db2都不是缺省就可以很輕松做到高并發的,但是處理的好,至少db2 可以做到不輸給oracle的高并發。 至于sql server ,tpc網站上去翻一下,可以發現sql server也是常客。

          但是早期oracle的開發, 嗯, 我覺得在很多方面其實倒不如db2這樣的數據庫省事,比如大表和小表在sql中的位置,都會顯著影響sql性能。再比如sql是簡單好,還是復雜好,這2個數據庫也是相反的。

          這只能說明不同數據庫的機制是有很大差異的,用好一個數據庫需要點時間對他進行比較深入的理解。現代程序員往往被各種框架屏蔽了底層,有時候也不是什么好事,以前項目中就有專門組織DBA對程序員進行數據庫方面的培訓,目的也就是為了彌補這個問題。

          對于鎖的問題,在oracle9i&10g編程藝術那本書里,作者有很深入的介紹,也列舉了其他數據庫的處理情況。作者從其他數據庫轉向使用oracle的時候,對這個問題,貌似和樓主一樣震驚,呵呵。當年我也有個項目,被db2的鎖機制,搞的的死去活來,呵呵。

          簡單的說,搖身要是高可靠性數據庫都只是知道寫sql這么簡單, 人家DBA還怎么活?  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決
          2008-06-21 19:50 | 鬼狗
          另外不知道lz用的jdbc是什么版本? sqlserver 2000 的官方版本問題多多,印象中諸多特性都不支持。  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決
          2008-06-22 15:24 | ronghao
          @鬼狗
          呵呵,你的意見非常中肯。  回復  更多評論
            
          # re: 高并發測試下的一些問題及解決
          2008-07-03 22:55 | leekiang
          汗,我們公司做了很多項目了,可你們說的這些問題公司幾十號人沒有一個人清楚,那些項目能用嗎?請問。  回復  更多評論
            
          <2008年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          關注工作流和企業業務流程改進。現就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

          常用鏈接

          留言簿(38)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          常去的網站

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 南昌县| 赣榆县| 东乌| 青岛市| 根河市| 香格里拉县| 新郑市| 万荣县| 宁化县| 射洪县| 闻喜县| 涟水县| 江源县| 枣阳市| 周口市| 桂阳县| 五华县| 瑞昌市| 象山县| 容城县| 彰化市| 油尖旺区| 都兰县| 清新县| 汤原县| 阳高县| 东兴市| 葫芦岛市| 宁夏| 瓦房店市| 股票| 双流县| 高碑店市| 赤水市| 台中县| 黑河市| 仙游县| 揭西县| 银川市| 屏东市| 洛南县|