多个线程(客队端)共享一个connection的问题. 如果其中一个事务执行了commit语句,其它事务修改的数据会不会也同时被commit? 
如果会,请问有没有方法可以让每个线程的事务独立,相互commit但不影响? 我知道不同的数据库处理可能不同,大家可以分别讨论不同数据库.这里只讨论多线程共享一个connection的问题。 如果为每次个线程(客队端)new 一个connection这个方法我知道,我只想讨论共享一个connection的可行性. 因为共享一个connection性能会更高.

解决方案 »

  1.   

    多个线程(客队端)共享一个connection的问题.   如果其中一个事务执行了commit语句,其它事务修改的数据会不会也同时被commit?  
    --------------
    会如果会,请问有没有方法可以让每个线程的事务独立,相互commit但不影响?   我知道不同的数据库处理可能不同,大家可以分别讨论不同数据库. 
    --------------
    一个客户端一个connection,如果担心connection太多,就用数据库连结池,取不到数据库连结的客户端会等待这里只讨论多线程共享一个connection的问题。   如果为每次个线程(客队端)new   一个connection这个方法我知道,我只想讨论共享一个connection的可行性.   因为共享一个connection性能会更高. 
    --------------
    不可行,每个客户端有相对独立的事务,所以不应该互相干扰
      

  2.   

    显然共享是不可取的!
    简单介绍连接池机制:
    1.项目启动时创建好初始数目的数据库连接,初始为空闲状态!这部分连接将永远不会断开,直到你的应用程序退出运行!
    2.当某个类要使用连接时,到连接池中随机找寻一个空闲状态的连接给此类使用,此时修改该连接状态为使用,此状态告诉其他类将不能再使用该连接,直到该连接重新被置成空闲状态!
    3.当该类使用完该连接以后调用close方法将该连接归还连接池,将状态修改为空闲状态!此处的close方法并不是真正的关闭连接,而是将连接放回到连接池中.
    4.当连接池中所有的连接都被使用,而又有新的使用连接请求时,那么连接池会自动去创建一个新的连接供使用,该新连接使用完后不会被断开,将永久留在连接池中.此时连接池中连接的数目将增加一个.
    5.直到连接池中的连接数目达到配置的最大数目,并且所有的连接都在被使用时,再有新的要使用连接的请求才会处于等待状态.但一般情况下该情况几乎不会发生.因为所有的地方同一时刻使用连接的并发几率很小!所以根据自己项目中并发情况来设置连接池中连接的数目.
    6.连接池里的连接在使用完后,必须调用相应的close方法将连接归还到连接池当中,这样才能保证连接池正常使用.否则长时间不归还连接会导致连接池无可用连接,从而导致应用无法操作.
      

  3.   

    谢谢大家. 
    to lip009: 连接池是很好的方案,不知道java本身有没有专门处理连接池相关的类? 我用过其它一些开发工具,有专门的连接池(类).
      

  4.   

    以前搞CS系统为主的,一般一个客户端一个连接,系统同时使用的用户不算多,所以没用上连接池. 现在搞BS程序,我就觉得可能连接池很有必要了, 太多的connect及disconnect操作会影响数据库性能,用户越多问题越严重.
      

  5.   

    不知道java本身有没有专门处理连接池相关的类?
    ________________________________________有的,DBCP和C3P0都是相当不错的连接池开源框架:
    DBCP http://commons.apache.org/dbcp/
    C3P0 http://sourceforge.net/projects/c3p0
      

  6.   

    如果是Web应用的话,不建议自己来管理连接池,一般使用应用服务器的JNDI数据源来配置连接池,
    让应用服务器来管理。像Tomcat的JNDI数据源底层就是使用DBCP来实现的。
      

  7.   

    to bao110908:  你是说tomcal本身就有这个功能了吗? 我根本不用管连接池这部分吗? 
    比如说:我执行以下代码,实际上是经常tomcat连接池处理,并不是直接连接或断开数据库,对吗? 如果是, 按照4楼所说原理,我执行close()后,只是与tomcat连接池断开联系,实际上并不是与数据库断开连接. 
    connection = DriverManager.getConnection(dburl, uid, pwd)
    connecttion.close()
      

  8.   

    上面打错字了:
    "实际上是经常tomcat连接池处理" => "实际上是经过tomcat连接池处理"
      

  9.   


    看到这个问题,我想到一个新的方法,不知道能不能实现:
    使用ThreadLocal来实现:
    写一个工具类来得到Connection:
    public class UtilConnection{
     
       private static ThreadLocal local = new TreadLocal();
       static {
           try{
               class.forName("oracle.jdbc.driver.DriverOracle");
           }catch(....){
           }
       }   public static Connection getCurrentConnection(){
             Connection con =(Connection) local.get();
             if(con == null){
                  con = DriverManager.getConnection();
                  local.set(con);
             }
             return con;
       }
       
       public static void closeConnection(){
              Connection con = (Connection) local.get();
              if(con != null){
                 con.close();
              }
              local.set(null);
       }
     
    }
    在使用时直接用:
    Connection con = UtilConnection.getCurrentConnection();
    不知道这样好不好,没测试过,高手说下,这样做可以不.
      

  10.   

    1.在Tomcat目录下conf/server.xml里配置你的web工程,同时配置连接池       <Context docBase="myweb" path="/myweb" reloadable="true">
       <ResourceParams name="jdbc/DBPool">
         <parameter>
           <name>factory</name> 
           <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
         </parameter>
         <parameter>
           <name>driverClassName</name> 
           <value>oracle.jdbc.driver.OracleDriver</value>
         </parameter>
         <parameter>
           <name>url</name>
           <value>jdbc:oracle:thin:@10.1.1.101:1521:orcl</value>
         </parameter>
         <parameter>
           <name>username</name>
           <value>oracle</value>
         </parameter>
         <parameter>
           <name>password</name>
           <value>oracle</value>
         </parameter>
         <parameter>
           <name>maxActive</name>
           <value>10</value>
         </parameter>
         <parameter>
           <name>maxIdle</name>
           <value>10</value>
         </parameter>
         <parameter>
           <name>maxWait</name>
           <value>-1</value>
         </parameter>
               </ResourceParams> </Context>2.在你的web工程里的web.xml配置JNDI
    <resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/DBPool</res-ref-name>注意这里的名字和上边连接池的名字要一致
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    </resource-ref>
      

  11.   

    3.数据库连接管理类/**
     * Author:BluesLee
     * CreateDate:2006-06-12 22:51:00
     * Modifier:BluesLee
     * ModifyDate:2006-06-12 22:51:00
     * Version:1.0
     * Copyright\u00A92006 xxxx 沪ICP备06××××××号
     * All right reserved.
     */
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.CallableStatement;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import org.apache.log4j.Logger;
    import java.sql.DriverManager;
    /**
     * 本类是数据库连接的管理类,因此在整个系统中没有必要出现多个,一个就够用了
     * 因此,决定在此类上使用单态设计模式,只提供本类的一个实例出去。
     * 在此我是用单态的饿汉模式进行使用
     */
    public class DBConnectionManager {
      private static Logger logger=Logger.getLogger(DBConnectionManager.class.getName());
      /**
       * 本静态变量用来存放本系统启动时由Struts生成的连接池的数据源
       */
      private static DataSource datasource;
      /**
       * 由于本类使用单态设计模式,因此不允许在使用中通过New进行实例化,那么本类就要提供一个
       * 此类的实例供外界使用,这就是供外界使用的实例
       */
      private static DBConnectionManager dbConManager=new DBConnectionManager();
      private DBConnectionManager(){}
      /**
       * 此静态方法用来向类的静态变量赋值,用来在系统中使用
       * @param mydatasource 传入的struts生成的数据源
       */
      public static void setDatasource(DataSource mydatasource) {
        logger.info("设置数据源");
        if(datasource==null){
          datasource = mydatasource;
        }
      }
      /**
       * 由于本类使用单态模式,不允许其他的类使用New进行创建实例
       * 因此在这里提供一个共有的静态方法来向外界提供自己的一个实例。
       * @return 返回本类的唯一实例
       */
      public static DBConnectionManager getInstance() {
        logger.info("获得数据库连接管理类的实例");
        return dbConManager;
      }
      /**
       * 此方法提供一个可用的数据库连接,从连接池中取得可用连接
       * @return 可用的数据库连接
       */
      public Connection getConnection() {
        Connection conn = null;
        try {
          logger.info("从连接池中获得空闲的数据库连接");
          logger.info(datasource);
          conn = datasource.getConnection();
          logger.info("拿到连接---------");
          return conn;
        }
        catch (SQLException ex) {
          ex.printStackTrace();
        }
        return null;
      }
      /**
       * 这是一个用来关闭所有的数据库连接相关的打开对象的方法,这样作的好处是不用在每一次调用了sql之后
       * 要写一大串的关闭操作。
       * @param conn 将要关闭的数据库连接
       * @param st 将要关闭的数据库操作对象
       * @param pst 将要关闭的预处理数据库操作对象
       * @param cst 将要关闭的数据库存储过程调用对象
       * @param rst 将要关闭的数据库记录集对象
       * @throws java.lang.Exception 有可能要抛出的异常
       */
      public void closeAll(Connection conn,Statement st,PreparedStatement pst,CallableStatement cst,ResultSet rst)
          throws Exception{
        if(rst!=null){
          rst.close();
        }
        if(st!=null){
          st.close();
        }
        if(pst!=null){
          pst.close();
        }
        if(cst!=null){
          cst.close();
        }
        if(conn!=null){
          conn.close();
        }
        logger.info("==========>关闭连接成功!");
      }
    }4.在servlet里获取数据源public class MyServlet extends HttpServlet {

    public MyServlet() {
    super();
    } public void init() throws ServletException {
        /**得到数据源*/
        try {
          Context initCtx = new InitialContext();
          DataSource datasource = (DataSource) initCtx.lookup(
              "java:comp/env/jdbc/MyDBA");
          DBConnectionManager.setDatasource(datasource);
          logger.info("DataSourcePlugIn已经初始化完成...");
        }
        catch (NamingException ex) {
          ex.printStackTrace();
        }
    }
    public void destroy() {
    super.destroy();
    } public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    }
    }5.在web.xml里配置该servlet在项目启动的时候加载  <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>MyServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
      </servlet>
      

  12.   

    6.在业务中使用该数据库连接  /**
       * 根据用户ID查询用户信息
       * @param doi 用户信息对象父接口,包含有用户ID参数
       * @return 返回查询结果对象父接口引用
       */
      public DataObjectIF findOne(DataObjectIF doi) {
        java.sql.Connection conn = null;
        java.sql.ResultSet rs = null;
        java.sql.PreparedStatement ps = null;    UserInfoData uid = (UserInfoData) doi;
        UserInfoData result = new UserInfoData();
        String sql = "select * from user_info where id=?";
        conn = DBConnectionManager.getInstance().getConnection();
        try {
          ps = conn.prepareStatement(sql);
          ps.setLong(1, uid.getId());
          rs = ps.executeQuery();
          if (rs.next()) {
            result.setId(rs.getLong("id"));
            result.setUsername(rs.getString("username"));
            result.setPassword(rs.getString("password"));
          }
        }
        catch (SQLException ex) {
          ex.printStackTrace();
        }
        finally {
          try {
            DBConnectionManager.getInstance().closeAll(conn, null, ps, null, rs);
          }
          catch (Exception ex1) {
            ex1.printStackTrace();
          }
        }
        return result;
      }
      

  13.   

    利用ThreadLocal管理数据源是hibernate采用的方式。
    j2ee对于每一个请求创建一个线程为其服务,ThreadLocal就是为每个线程保存资源的工具。
    链接con共享肯定是不可能的,那样事务根本没法管理,更别说复杂的事务管理了。
    连接池属于链接复用而不是链接共享,con链接在同一时刻是为一个客户服务的直到客户归还了该链接。
      

  14.   

    我提出共享一个connection的想法,是因为我知道sql server 在一个connection 中 可以分成n个transaction, 而commit的时候,也是可以针对某个transaction来提交, 从这个理论来看, 多个用户使用同一个connection 但又相互不影响大家保存数据,这好象是可能的, 但我没具体实践过. 或许不是所有的数据库都支持.
      

  15.   

    能不能提供个VC的?我的这个程序出问题,帮帮忙看下~
    BOOL CPatientLogin::OnInitDialog()
    {
    CDialog::OnInitDialog();

    CString ListID; m_fy.AddString("1元");
    m_fy.AddString("2元");
    m_fy.AddString("3元");

    _ConnectionPtr m_pConnection;
    _CommandPtr m_pCommand;
    _RecordsetPtr m_pRecordset; m_pConnection.CreateInstance(_uuidof(Connection));
    m_pRecordset.CreateInstance(_uuidof(Recordset));
    m_pCommand.CreateInstance("ADODB.COMMAND");
    try{
    _bstr_t strConnect = "driver={SQL Server};server=CHINESE-20171AC\\SQLEXPRESS;DATABASE=HISdata;UID=bbs;PWD=bbs111;";
    m_pConnection->Open(strConnect,"","",-1);
       CString strSQL="select * from Department";
        BSTR bstrSQL=strSQL.AllocSysString();
       m_pRecordset->Open(bstrSQL,(IDispatch *)m_pConnection,adOpenDynamic,adLockOptimistic,adCmdText);
       _variant_t varValue;
       varValue = m_pRecordset->Fields->GetItem("DepartmentID")->Value;
       if(varValue.vt!=VT_NULL){
       while(!m_pRecordset->adoEOF)

    m_ks.AddString((char *)_bstr_t(varValue = m_pRecordset->Fields->GetItem("DepartmentID")->Value));
    m_pRecordset->MoveNext();
               }
            }
       strSQL="select * from PatientLogin";
        bstrSQL=strSQL.AllocSysString();
        m_pRecordset->Open(bstrSQL,(IDispatch*)m_pConnection,adOpenDynamic,adLockOptimistic,adCmdText);  varValue=m_pRecordset->Fields->GetItem("CaseID")->Value;
     if(varValue.vt!=VT_NULL){
     m_pRecordset->MoveLast();
     ListID=(char *)_bstr_t(varValue = m_pRecordset->Fields->GetItem("CaseID")->Value);
         int m=atoi(ListID);
     m++;
     m_mz.SetWindowText(_bstr_t(m));
     }
    }
    catch(_com_error e)
      {
      AfxMessageBox(e.Description());
      }
      m_pRecordset->Close();
    return TRUE;
     }
    出错是从颜色标记处开始的