如何在JDBC中build立连接池?
任何人都可以提供有关如何build立JDBC连接池的示例或链接?
从谷歌search我看到很多不同的方式做这个,这是相当混乱。
最终我需要的代码返回一个java.sql.Connection
对象,但我有麻烦入门..欢迎任何build议。
更新:不是javax.sql
或java.sql
有池连接实现吗? 为什么不最好使用这些?
如果你需要一个独立的连接池,我偏好C3P0而不是DBCP (我在前面的回答中提到过 ),在负载很重的情况下,DBCP的问题太多了。 使用C3P0非常简单。 从文档 :
ComboPooledDataSource cpds = new ComboPooledDataSource(); cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" ); cpds.setUser("swaldman"); cpds.setPassword("test-password"); // the settings below are optional -- c3p0 can work with defaults cpds.setMinPoolSize(5); cpds.setAcquireIncrement(5); cpds.setMaxPoolSize(20); // The DataSource cpds is now a fully configured and usable pooled DataSource
但是,如果您正在应用程序服务器中运行,我会build议使用它提供的内置连接池。 在这种情况下,您需要对其进行configuration(请参阅应用程序服务器的文档)并通过JNDI检索数据源:
DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS");
通常如果你需要一个连接池,你正在编写一个在一些托pipe环境中运行的应用程序,那就是你正在一个应用程序服务器中运行。 如果是这种情况, 请确保在尝试任何其他选项之前检查您的应用程序服务器提供的连接池设施 。
开箱即用的解决scheme将与其他应用程序服务器设施最佳结合。 但是如果你没有在应用程序服务器中运行,我会推荐Apache Commons DBCP组件 。 它被广泛使用,并提供大多数应用程序所需的所有基本池function。
我会build议使用commons-dbcp库。 列举了很多例子 ,如何使用它,这里是简单的移动链接。 用法很简单:
BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName("oracle.jdbc.driver.OracleDriver") ds.setUsername("scott"); ds.setPassword("tiger"); ds.setUrl(connectURI); ... Connection conn = ds.getConnection();
您只需要创build一次数据源,因此如果您不知道如何执行该操作,请务必阅读文档。 如果您不知道如何正确编写JDBC语句,以免泄漏资源,那么您也可能需要阅读这个Wikipedia页面。
不要重新发明轮子。
尝试一个现成的第三方组件:
- Apache DBCP – 这个由Tomcat内部使用,真正由你使用。
- C3P0
Apache DBCP附带了关于如何设置池javax.sql.DataSource的不同示例。 这里有一个样本可以帮助你开始。
在应用程序服务器中,我使用的是我工作的地方(Oracle应用服务器10g,我记得),池由应用程序服务器处理。 我们使用带有javax.sql.DataSource
的JNDI查找来检索javax.sql.InitialContext
。
它做了这样的事情
try { context = new InitialContext(); jdbcURL = (DataSource) context.lookup("jdbc/CachedDS"); System.out.println("Obtained Cached Data Source "); } catch(NamingException e) { System.err.println("Error looking up Data Source from Factory: "+e.getMessage()); }
(我们没有写这个代码,它是从这个文档复制的。)
HikariCP
它很现代,速度很快,很简单。 我用它来为每个新项目。 我比C3P0更喜欢它,不太了解其他游泳池。
正如其他人所回答的,您可能会对Apache Dbcp或c3p0感到满意。 两者都很受欢迎,而且工作得很好。
关于你的疑问
不是javax.sql或java.sql有连接实现吗? 为什么不最好使用这些?
他们不提供实现,而是接口和一些支持类,只对实现第三方库(池或驱动程序)的程序员表示赞赏。 通常你甚至不看这个。 您的代码应该以透明的方式处理来自池的连接,就像它们是“普通”连接一样。
Vibur DBCP是另一个用于此目的的库。 下面几个例子展示了如何configurationHibernate,Spring + Hibernate或者编程方式,可以在它的网站上find: http : //www.vibur.org/
另请参阅此处的免责声明。
池
- 共享机制是提前创build对象的方式。 当一个类被加载。
- 它提高了应用程序的
performance
[通过使用相同的对象来执行对象数据的任何操作]和memory
[分配和取消分配许多对象会造成显着的内存pipe理开销]。 - 因为我们使用相同的对象,因此不需要清理对象,从而减less垃圾收集负载。
«Pooling [ Object
池, String
常量池, Thread
池,连接池]
string常量池
- string文字池只维护每个不同string值的一个副本。 这必须是不可改变的。
- 调用intern方法时,使用equals方法检查池中相同内容的对象可用性。 «如果string复制在池中可用,则返回参考。 否则,String对象被添加到池中并返回引用。
示例:用于validation池中的唯一对象的string。
public class StringPoolTest { public static void main(String[] args) { // Integer.valueOf(), String.equals() String eol = System.getProperty("line.separator"); //java7 System.lineSeparator(); String s1 = "Yash".intern(); System.out.format("Val:%s Hash:%s SYS:%s "+eol, s1, s1.hashCode(), System.identityHashCode(s1)); String s2 = "Yas"+"h".intern(); System.out.format("Val:%s Hash:%s SYS:%s "+eol, s2, s2.hashCode(), System.identityHashCode(s2)); String s3 = "Yas".intern()+"h".intern(); System.out.format("Val:%s Hash:%s SYS:%s "+eol, s3, s3.hashCode(), System.identityHashCode(s3)); String s4 = "Yas"+"h"; System.out.format("Val:%s Hash:%s SYS:%s "+eol, s4, s4.hashCode(), System.identityHashCode(s4)); } }
使用第三方库 使用Type-4 驱动程序的连接池 [ DBCP2
, c3p0
, Tomcat JDBC
]
Type 4 - The Thin driver converts JDBC calls directly into the vendor-specific database protocol Ex[Oracle - Thick, MySQL - Quora].
维基
在连接池机制中,当类加载时,它获得了physical JDBC connection
对象,并为用户提供了一个包装的物理连接对象。 PoolableConnection
是实际连接的一个包装。
-
getConnection()
从连接对象池中select一个空闲的包装连接并返回它。 -
close()
而不是closures它将包裹连接返回到池。
示例:在Java 7中使用〜DBCP2连接池[ try-with-resources
]
public class ConnectionPool { static final BasicDataSource ds_dbcp2 = new BasicDataSource(); static final ComboPooledDataSource ds_c3p0 = new ComboPooledDataSource(); static final DataSource ds_JDBC = new DataSource(); static Properties prop = new Properties(); static { try { prop.load(ConnectionPool.class.getClassLoader().getResourceAsStream("connectionpool.properties")); ds_dbcp2.setDriverClassName( prop.getProperty("DriverClass") ); ds_dbcp2.setUrl( prop.getProperty("URL") ); ds_dbcp2.setUsername( prop.getProperty("UserName") ); ds_dbcp2.setPassword( prop.getProperty("Password") ); ds_dbcp2.setInitialSize( 5 ); ds_c3p0.setDriverClass( prop.getProperty("DriverClass") ); ds_c3p0.setJdbcUrl( prop.getProperty("URL") ); ds_c3p0.setUser( prop.getProperty("UserName") ); ds_c3p0.setPassword( prop.getProperty("Password") ); ds_c3p0.setMinPoolSize(5); ds_c3p0.setAcquireIncrement(5); ds_c3p0.setMaxPoolSize(20); PoolProperties pool = new PoolProperties(); pool.setUrl( prop.getProperty("URL") ); pool.setDriverClassName( prop.getProperty("DriverClass") ); pool.setUsername( prop.getProperty("UserName") ); pool.setPassword( prop.getProperty("Password") ); pool.setValidationQuery("SELECT 1");// SELECT 1(mysql) select 1 from dual(oracle) pool.setInitialSize(5); pool.setMaxActive(3); ds_JDBC.setPoolProperties( pool ); } catch (IOException e) { e.printStackTrace(); } catch (PropertyVetoException e) { e.printStackTrace(); } } public static Connection getDBCP2Connection() throws SQLException { return ds_dbcp2.getConnection(); } public static Connection getc3p0Connection() throws SQLException { return ds_c3p0.getConnection(); } public static Connection getJDBCConnection() throws SQLException { return ds_JDBC.getConnection(); } } public static boolean exists(String UserName, String Password ) throws SQLException { boolean exist = false; String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?"; try ( Connection connection = ConnectionPool.getDBCP2Connection(); PreparedStatement pstmt = connection.prepareStatement(SQL_EXIST); ) { pstmt.setString(1, UserName ); pstmt.setString(2, Password ); try (ResultSet resultSet = pstmt.executeQuery()) { exist = resultSet.next(); // Note that you should not return a ResultSet here. } } System.out.println("User : "+exist); return exist; }
jdbc:<DB>:<drivertype>:<HOST>:<TCP/IP PORT>:<dataBaseName>
jdbc:
oracle
:thin:@localhost:1521:myDBName
jdbc:
mysql
://localhost:3306/myDBName
connectionpool.properties
URL : jdbc:mysql://localhost:3306/myDBName DriverClass : com.mysql.jdbc.Driver UserName : root Password :
Web应用程序: 为了避免所有连接closures时出现连接问题[MySQL“wait_timeout”默认8小时],以重新打开与底层数据库的连接。
你可以这样做,通过设置testOnBorrow = true和validationQuery =“SELECT 1”来testing每个连接,并且不推荐使用autoReconnect for MySQL服务器。 问题
===== ===== context.xml ===== ===== <?xml version="1.0" encoding="UTF-8"?> <!-- The contents of this file will be loaded for a web application --> <Context> <Resource name="jdbc/MyAppDB" auth="Container" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" type="javax.sql.DataSource" initialSize="5" minIdle="5" maxActive="15" maxIdle="10" testWhileIdle="true" timeBetweenEvictionRunsMillis="30000" testOnBorrow="true" validationQuery="SELECT 1" validationInterval="30000" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/myDBName" username="yash" password="777" /> </Context> ===== ===== web.xml ===== ===== <resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/MyAppDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> ===== ===== DBOperations ===== ===== servlet « init() {} Normal call used by sevlet « static {} static DataSource ds; static { try { Context ctx=new InitialContext(); Context envContext = (Context)ctx.lookup("java:comp/env"); ds = (DataSource) envContext.lookup("jdbc/MyAppDB"); } catch (NamingException e) { e.printStackTrace(); } }
也看到这些:
- AM-I-使用-JDBC的连接池
- configuration-JDBC池,高并发
Apache Commons有一个用于这个目的的库: DBCP 。 除非你对池有奇怪的要求,否则我会使用一个库,因为它肯定会比你想象的更加棘手和微妙。
你应该考虑使用UCP。 通用连接池(UCP)是一个Java连接池。 它是一个function丰富的连接池,并与Oracle的Real Application Clusters(RAC),ADG,DG数据库紧密集成。
有关UCP的更多详细信息,请参阅此页面 。
MiniConnectionPoolManager
是一个单一的java文件的实现,如果你正在寻找一个可embedded的解决scheme,并不太关心性能(虽然我没有在这方面进行testing)。
它是多执照的EPL , LGPL和MPL 。
其文档还提供了值得检查的选项(在DBCP和C3P0上):
- Proxool的
- BoneCP
- Tomcat JDBC连接池