沉睡森林@漂在北京

本处文章除注明“转载”外均为原创,转载请注明出处。

  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 王总兵 阅读(136) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: