代码之家  ›  专栏  ›  技术社区  ›  westmark

JDBC基本概念、池和线程

  •  8
  • westmark  · 技术社区  · 7 年前

    在单线程环境中,我总是在Javase中使用JDBC。但是现在我需要使用一个连接池,让许多线程与数据库(mssql和oracle)进行交互,而且我很难做到这一点,因为我似乎缺少一些基本的API不存在。

    afaik连接和登录后 Connection 表示与数据库的物理TCP/IP连接。它创造 Statement 可以被视为与数据库在 连接 .

    • 事务和回滚在哪里出现?是在 连接 声明 水平。
    • “一”字安全吗? 连接 创建n个语句并将其赋给不同的线程,以便让每个线程都使用它 陈述 是吗?

    如果没有,在配置池之后,如下所示:

    OracleDataSource ods = new OracleDataSource(); 
    ods.setURL("jdbc:oracle:thin:@tnsentryname");
    ods.setUser("u");
    ods.setPassword("p");
    
    • 顺便问一下,在哪里设置连接池大小?

    • 为了正确使用连接,我在每个线程中都会这样做吗?

    //thead run方法

    Connection conn = ods.getConnection();
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("the sql");
    // do what I need to do with rs
    rs.close();
    int updateStatus = stmt.executeUpdate("the update");
    stmt.close();
    conn.close();
    

    //线程结束运行方法

    • 如果池的任何物理连接以某种方式崩溃或中断,池是否会自动尝试重新连接并在池中插入新连接,以便随后的池.getConnection()只获得健康连接?

    非常感谢,请原谅我的英语不好。

    7 回复  |  直到 7 年前
        1
  •  6
  •   teabot    17 年前

    连接池用自己的包装器实现来修饰连接和语句实例。当您在连接上调用close时,实际上只是将其释放回池中。当对准备好的语句调用close时,实际上只是将其释放回连接的语句缓存。准备语句时,可能只是从连接中获取缓存语句实例。所有这些都隐藏在视野之外,这样你就不用担心了。

    当一个连接被提供给一个客户机时,它将不再可供任何其他客户机使用,直到该连接被释放回池为止。通常只需在需要时获取连接,然后在完成连接后立即返回。因为连接在池中保持打开状态,所以在获取和释放连接时开销很小。

    您应该像使用单个JBDC连接一样使用来自池的连接,并遵循有关关闭资源的最佳实践,这样就不会泄漏任何连接或语句。请参阅其他一些答案中的Try/Catch/Finally示例。

    池可以管理连接资源,并在将它们分发给客户机之前对它们进行测试,以确保它们不会过时。此外,池还将根据需要创建和销毁连接。

        2
  •  7
  •   Jay    17 年前

    如果您已经掌握了单线程的JDBC,那么访问多线程和连接池就不算什么了。你需要做的就是:1。当需要连接时,请从池中获取,而不是直接获取。2。每个线程都应该有自己的连接。

    为了澄清第2点:如果您得到一个连接,然后将它传递给多个线程,那么您可以有两个线程同时尝试对同一个连接执行查询。Java将在此上引发异常。每个连接只能有一个活动语句,每个语句只能有一个活动查询(即resultset)。如果两个线程都持有相同的连接对象,那么它们很可能会立即违反此规则。

    另一个警告是:对于连接池,在完成连接后要非常小心地关闭连接。池管理器没有明确的方法来知道您何时完成连接,因此如果您无法关闭连接,它将在那里挂起很长一段时间,可能永远取决于池管理器。我总是使用try块跟踪每个“getConnection”,并关闭finally块中的连接。然后我知道我已经在函数退出之前关闭了它。

    除此之外,一切都应该和你习惯的一样。

        3
  •  3
  •   rjmunro    17 年前
    1. 事务发生在连接级别。

    2. 不是。通常,JDBC驱动程序会确保在另一个连接处于活动状态时,不能在同一个连接上执行第二个语句。

    如果需要连接池,请尝试 DBCP framework .它提供了相当不错的故障处理(比如注意到过时的连接和客户机代码没有返回的连接)。

    至于您的代码:总是将代码包装在 try{...}finally{...} :

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    try {
         conn = ds.getConnection ();
         stmt = ...
         rs = ...
    }
    finally {
         rs = close (rs);
         stmt = close (stmt);
         conn = close (conn);
    }
    
    public static Connection close (Connection conn) {
        if (conn != null) {
            try {
                conn.close ();
            }
            catch (SQLException e) {
                e.printStackTrace(); // Log, don't rethrow!!
            }
        }
        return null;
    }
    

    此代码将确保所有连接等始终正确关闭,并且关闭期间的任何异常都不会隐藏以前的错误。

        4
  •  2
  •   Yishai    17 年前

    我认为你应该从太阳开始 tutorial 在连接池上。除此之外,还有许多连接池的实现,一些开放源代码,包括 one from Apache . 你应该从那里开始,而不是在这里重新发明轮子。

        5
  •  1
  •   Nick    17 年前

    在任何给定的连接上只能打开一条语句。使用连接池创建多个连接并不那么困难,不过要做到这一点,最好是使用一个更常用的连接池。

    另外,如果您要使用标准JDBC,我建议使用PreparedStatement over语句。

    我一直在使用iBATIS,开箱即用很不错。把其他一些东西也带到桌子上。

        6
  •  0
  •   Everyone    17 年前

    this (+):

        7
  •  0
  •   djna    17 年前

    额外位:

    1. 应用服务器倾向于提供连接池,它可以变得相当聪明。如果您使用的是应用服务器,请在添加自己的任何内容之前仔细调查一下您从这个盒子中得到了什么。

    2. 交易:如果有

      开始事务

      获得联系 工作 关闭连接//表示返回池

      连接(具有相同的隔离等级等)
      你会得到 同样 连接,池为您的事务保留它

      工作//发生在同一个交易中 闭合连接

      提交事务//提交所有工作

    3. 连接和错误

    池实现可能很聪明。如果来自池的任何一个连接遇到某些错误,表明DB服务器已弹回,则池可以选择丢弃所有池成员。

    推荐文章