JDBC基本概念,池和线程

时间:2009-08-13 14:50:06

标签: java oracle multithreading jdbc connection-pooling

我总是在单线程环境中使用JavaSE中的JDBC。但是现在我需要使用一个连接池,让许多线程与数据库(MSSQL和Oracle)进行交互,我很难尝试实现它,因为我似乎缺少api的一些基本功能。< / p>

连接并记录Connection后的AFAIK表示与数据库的物理tcp / ip连接。它创建Statement(s),可以将其视为与Connection上的数据库的SQL交互。

  • 交易和回滚在哪里?是Connection还是Statement级别。
  • 'one'Connection创建N个语句并将其分配给不同的线程,以便让每个人拥有Statement的使用权,是否安全?

如果没有,并且在配置了这样的池之后:

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

  • 为了正确使用连接,这是我在每个线程中要做的吗?

// thead run method

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();

//线程运行方法结束

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

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

7 个答案:

答案 0 :(得分:7)

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

澄清第2点:如果您获得连接然后将其传递给多个线程,则可能有两个线程尝试同时对同一连接执行查询。 Java会抛出异常。每个连接只能有一个活动语句,每个语句只能有一个活动查询(即ResultSet)。如果两个线程都持有相同的Connection对象,则它们可能会立即违反此规则。

另一个警告:使用连接池时,要非常小心,在完成后始终关闭连接。池管理器没有明确的方法来知道你何时完成了连接,所以如果你没有关闭一个,那么它会在那里闲置很长一段时间,可能永远取决于池管理器。我始终总是使用try块跟随每个“getConnection”,并关闭finally块中的连接。然后我知道在函数退出之前我已经关闭了它。

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

答案 1 :(得分:6)

连接池使用自己的包装器实现来装饰Connection和Statement实例。当您在连接上调用close时,实际上只是将其释放回池中。当您在预准备语句上调用close时,实际上只是将其释放回连接的语句缓存。准备语句时,您可能只是从连接中获取缓存的语句实例。所有这些都隐藏在视图中,因此您不必担心它。

当连接被提供给客户端时,在将连接释放回池之前,任何其他客户端都不再可以使用它。您通常只在需要时获取连接,然后在完成后立即返回它们。由于连接在池中保持打开状态,因此获取和释放连接的开销很小。

您应该像使用单个JBDC连接一样使用池中的连接,并遵循有关资源关闭的最佳实践,这样您就不会泄漏任何连接或语句。在其他一些答案中查看try / catch / finally示例。

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

答案 2 :(得分:3)

  1. 交易发生在连接级别。

  2. 没有。通常,JDBC驱动程序将确保您无法在同一连接上执行第二个语句而另一个语句处于活动状态。

  3. 如果您需要连接池,请尝试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;
    }
    

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

答案 3 :(得分:2)

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

答案 4 :(得分:1)

您只能在任何给定的连接上保持一个Statement打开。使用连接池创建多个连接并不困难,但要采用的方法之一就是使用其中一个更常用的连接。

另外,如果你要采用标准JDBC的方式,我建议使用PreparedStatement而不是Statement。

我一直在使用iBatis,开箱即用非常好。还带来了一些其他的东西。

答案 5 :(得分:0)

this(+:

答案 6 :(得分:0)

额外位:

  1. 应用程序服务器倾向于提供连接池,它可以变得非常聪明。如果您使用的是app服务器,请在添加任何内容之前仔细调查您的内容。

  2. 交易:如果你有

    开始交易

    获得联系  工作  关闭连接//意味着返回池

    获得连接(具有相同的隔离级别等)
             //您将获得 SAME 连接,该池会为您的交易保留

    工作//在相同的交易中发生  关闭连接

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

  3. 连接和错误

  4. 池实现可以很聪明。如果池中的任何一个连接遇到某些错误,这些错误表明数据库服务器已退回,则池可以选择丢弃所有池成员。