Java JDBC基本概念、池和线程
我总是在单线程环境中使用JavaSE中的JDBC。但现在我需要使用一个连接池,让许多线程与数据库(MSSQL和Oracle)进行交互,我很难做到这一点,因为我似乎对api缺乏一些基本的了解 连接并记录后的AFAIKJava JDBC基本概念、池和线程,java,oracle,multithreading,jdbc,connection-pooling,Java,Oracle,Multithreading,Jdbc,Connection Pooling,我总是在单线程环境中使用JavaSE中的JDBC。但现在我需要使用一个连接池,让许多线程与数据库(MSSQL和Oracle)进行交互,我很难做到这一点,因为我似乎对api缺乏一些基本的了解 连接并记录后的AFAIK连接表示与数据库的物理tcp/ip连接。它创建的语句可以看作是通过连接与数据库的SQL交互 事务和回滚从何而来?是在连接还是语句级别 “一个”Connection创建N个语句并将其提供给不同的线程,以便让每个线程都拥有该语句的使用权,这样安全吗 如果没有,则在配置池后,如下所示:
连接
表示与数据库的物理tcp/ip连接。它创建的语句可以看作是通过连接与数据库的SQL交互
- 事务和回滚从何而来?是在
连接
还是语句
级别
- “一个”
Connection
创建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();
//线程结束运行方法
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()只获得健康连接
非常感谢,请原谅我的英语不好
事务发生在连接级别
不可以。通常,JDBC驱动程序会确保在另一条语句处于活动状态时,不能在同一个连接上执行第二条语句
如果需要连接池,请尝试。它提供了相当不错的故障处理(比如注意陈旧的连接和客户端代码未返回的连接)
至于您的代码:始终将代码包装在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;
}
此代码将确保所有连接等始终正确关闭,并且关闭期间的任何异常都不会隐藏以前的错误。我认为您应该从Sun on connection pooling开始。除此之外,还有许多连接池的实现,一些是开源的,包括。你真的应该从这里开始,而不是在这里重新发明轮子。连接池用它们自己的包装器实现装饰连接和语句实例。当您在连接上调用close时,实际上只是将其释放回池中。在对准备好的语句调用close时,实际上只是将其释放回连接的语句缓存。准备语句时,可能只是从连接中获取缓存语句实例。所有这些都隐藏在视线之外,所以你不必担心
将连接提供给客户端时,在将连接释放回池之前,任何其他客户端都无法再使用该连接。通常,您只需在需要连接时获取连接,然后在完成连接后立即返回。因为连接在池中保持打开状态,所以获取和释放连接的开销很小
您应该像使用单个JBDC连接一样使用池中的连接,并遵循有关关闭资源的最佳实践,以避免泄漏任何连接或语句。请参阅其他一些答案中的try/catch/finally示例
池可以管理连接资源并在将它们分发给客户端之前对其进行测试,以确保它们不会过时。此外,池将根据需要创建和销毁连接。在任何给定的连接上,只能保持一条语句处于打开状态。使用连接池创建多个连接并不困难,尽管方法是使用其中一个更常用的连接
此外,如果您打算采用标准JDBC,我建议使用PreparedStatement而不是Statement
我一直在使用iBatis,开箱即用非常好。还带来了一些其他的东西 看看(+:额外的位:
应用服务器倾向于提供连接池,它可以变得非常聪明。如果你正在使用应用服务器,在添加任何你自己的东西之前,仔细调查你从盒子里得到了什么
交易:如果你有
开始交易
接通
工作
关闭连接//意味着返回池
获取连接(具有相同的隔离级别等)
//您将获得相同的连接,池将为您的交易保留该连接
工作/发生在同一交易中
密切联系
提交事务//提交所有工作
连接和错误
池实现可能很聪明。如果池中的任何一个连接遇到某些错误,表明DB服务器已反弹,那么池可以选择放弃所有池成员。如果您已经掌握了单线程JDBC,那么使用多线程和连接池应该不是什么大问题。您需要做的就是不同的是:1.当你需要连接时,从池中获取,而不是直接获取。2.每个线程都应该有自己的连接
澄清第2点:如果您获得一个连接,然后将其传递给多个线程,那么可能会有两个线程同时尝试对同一个连接执行查询。Java将对此抛出异常。每个连接只能有一个活动语句和一个活动查询(即ResultSet)如果两个线程都持有相同的连接对象,它们很可能会立即违反此规则
还有一个警告:使用连接池时,请务必非常小心地在完成连接后关闭连接。池管理器没有确定的方法来关闭连接