沉睡森林@漂在北京

          本處文章除注明“轉載”外均為原創,轉載請注明出處。

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            152 隨筆 :: 4 文章 :: 114 評論 :: 0 Trackbacks
          下面的代碼是我在研究數據庫連接池化和事物控制時寫的,看似沒有什么問題的代碼,其實隱藏了一個十分嚴重的問題。
          1.
          package com.example.ds;

          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.SQLException;
          import java.util.ArrayList;
          import java.util.Collection;
          import java.util.HashMap;
          import java.util.List;

          //import java.util.concurrent.ConcurrentHashMap;

          public class ConnectFactory {

              
          private HashMap<String, UserConn> userConnPools;
              
          private static int MAX_CONN_NUM = 15;
              
          public ArrayList<Connection> idleConnPools;

              
          private ConnectFactory() {
                  userConnPools 
          = new HashMap<String, UserConn>();
                  idleConnPools 
          = new ArrayList<Connection>();

                  
          try {
                      Class.forName(
          "org.gjt.mm.mysql.Driver").newInstance();
                  } 
          catch (Exception e) {
                      e.printStackTrace();
                      System.out.println(
          "==>注冊驅動程序錯誤!");
                  }
                  
          for (int i = 0; i < MAX_CONN_NUM; i++) {
                      
          try {
                          Connection conn 
          = DriverManager.getConnection("jdbc:mysql://localhost/jpetstore?user=mysql_user&password=sa&useunicode=true&characterencoding=utf8");
                          idleConnPools.add(conn);
                      } 
          catch (SQLException e) {
                          e.printStackTrace();
                          System.out.println(
          "==>初始化idleConnPools錯誤!");
                      }
                  }
                  System.out.println(
          "==>注冊Connection成功!");
              }

              
          // private ConnPools connPools;
              private static final ConnectFactory _instance = new ConnectFactory();

              
          public static ConnectFactory getInstance() {
                  
          return _instance;
              }

              
          public Connection getConn() {
                  String threadId 
          = com.example.thread.ThreadValue.getThreadId();
                  System.out.println(
          "==>獲取線程號:" + threadId);
                  UserConn userConn 
          = null;
                  
          try {
                      userConn 
          = userConnPools.get(threadId);
                  } 
          catch (Exception e) {
                      
          // TODO: handle exception
                      System.out.println("==>獲取UserConn錯誤!");
                  }

                  
          if (userConn == null) {
                      
          if (idleConnPools.size() > 0) {
                          Connection conn 
          = idleConnPools.remove(idleConnPools.size() - 1);
                          userConn 
          = new UserConn(conn);
                          userConnPools.put(threadId, userConn);
                      } 
          else {
                          
          throw new RuntimeException("所有可以使用的連接均在使用中!");
                      }
                  }
                  System.out.println(
          "分配Conn成功,線程號:" + threadId);
                  
          return userConn.getConn();
              }

              
          public void closeConn() {
                  String threadId 
          = com.example.thread.ThreadValue.getThreadId();
                  UserConn userConn 
          = userConnPools.remove(threadId);
                  
          if (userConn != null) {
                      Connection conn 
          = userConn.getConn();
                      idleConnPools.add(conn);
                      userConn.closeConn();
                  } 
          else {
                      
          throw new RuntimeException("返回不需要使用的連接時錯誤!");
                  }
              }

              
          public List getIdelConnPools() {
                  
          return idleConnPools;
              }

              
          public Collection<UserConn> getUserConnPools() {
                  
          return userConnPools.values();
              }

          }


          2.
          package com.example.ds;

          import java.sql.Connection;

          public class UserConn {

              
          private static int count_num = 0;
              
          private Connection conn;
              
          private int flowId = 0;
              
          private boolean beUsed;
              
          private String threadId;

              
          public boolean isBeUsed() {
                  
          return beUsed;
              }

              
          public String getThreadId() {
                  
          return threadId;
              }

              
          public UserConn(Connection conn1) {
                  flowId 
          = count_num++;
                  beUsed 
          = false;
                  conn 
          = conn1;
              }

              
          public Connection getConn() {
                  beUsed 
          = true;
                  
          return conn;
              }

              
          public void closeConn() {
                  beUsed 
          = false;
              }

              
          public String toString() {
                  
          return (new StringBuffer()).append("==>UserConn=[flowId=").append(flowId).append(",beUsed=").append(beUsed).append("]").toString();
              }

          }


          當多個線程同時訪問ConnectFactory時,ConnectFactory的getConn和closeConn方法在處理ArrayList和HashMap時就面臨著同步的問題。即兩個線程同時獲取到了一個idle的Conn,而userConnPools里面就會有一個重復的Conn,導致事物上面處理的混亂。


          posted on 2009-03-07 16:08 王總兵 閱讀(192) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 长白| 丽水市| 句容市| 新乡县| 环江| 武邑县| 金平| 凌云县| 合作市| 芒康县| 政和县| 桂平市| 淮安市| 阿城市| 临泽县| 邹平县| 夏河县| 九江县| 清水县| 灵璧县| 扶风县| 栾川县| 田林县| 麦盖提县| 铁力市| 都昌县| 郎溪县| 东乡| 阿荣旗| 肥西县| 松原市| 昆山市| 鄂伦春自治旗| 孟村| 温宿县| 临武县| 菏泽市| 扎兰屯市| 教育| 当雄县| 东山县|