万字详解数据库连接池

数据库连接池的概念

  • 数据库连接是一种关键的、有限的、昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。
  • 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。这项技术能明显提高对数据库操作的性能。

自定义连接池

  • java.sql.DataSource接口:数据源(数据库连接池)。java官方提供的数据库连接池规范(接口)
    • 获取数据库连接对象:Connection getConnection();

工具类:

package com.dataSource;import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class JDBCUtils {/*** 1.私有构造方法*/private JDBCUtils() {}// 2.声明配置信息变量private static String driverClass;private static String url;private static String username;private static String password;private static Connection con;// 3.静态代码块中实现加载配置文件和注册驱动static {try {// 通过类加载器返回配置文件的字节流// getClassLoader().getResourceAsStream:通过给定名称查找资源,查询资源的规则由给定的类的class load来实现,这个方法由类的loader来执行;如果这个类由bootstrap加载,那么方法由ClassLoader.getSystemResourceAsStream代理执行。InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties");// 创建Properties集合,加载流对象的信息Properties prop = new Properties();prop.load(is);// 获取信息为变量赋值driverClass = prop.getProperty("driverClass");url = prop.getProperty("url");username = prop.getProperty("username");password = prop.getProperty("password");// 注册驱动Class.forName(driverClass);} catch (Exception e) {e.printStackTrace();}}//4.获取数据库连接的方法public static Connection getConnection() {try {con = DriverManager.getConnection(url, username, password);} catch (SQLException e) {e.printStackTrace();}return con;}//5.释放资源的方法public static void close(Connection con, Statement stat, ResultSet rs) {if (con != null) {try {con.close();} catch (SQLException e) {e.printStackTrace();}}if (stat != null) {try {stat.close();} catch (SQLException e) {e.printStackTrace();}}if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}}public static void close(Connection con, Statement stat) {close(con, stat, null);}
}

自定义连接池:

package com.dataSource;import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;public class MyDataSource implements DataSource {// 定义集合容器,用于保存多个数据库连接对象private static final List<Connection> POOP = Collections.synchronizedList(new ArrayList<>());// 静态代码块,生成10个数据库连接保存到集合中static {for (int i = 0; i < 10; i++) {Connection coon = JDBCUtils.getConnection();POOP.add(coon);}}@Overridepublic Connection getConnection() throws SQLException {if (POOP.size() > 0) {Connection remove = POOP.remove(0);return remove;} else {throw new RuntimeException("连接数量耗尽");}}/**定义getSize方法,获取连接池容器的大小*/public int getSize() {return POOP.size();}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}
}

测试类:

package com.dataSource;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class DataSourceTest {public static void main(String[] args) throws SQLException {// 创建连接池对象MyDataSource dataSource = new MyDataSource();System.out.println("使用之前连接池数量:" + dataSource.getSize());// 通过连接池对象获取连接对象Connection conn = dataSource.getConnection();// 查看DriverManager连接的实现类,发现是JDBC4ConnectionSystem.out.println(conn.getClass());// 查询学生表的全部信息String sql = "SELECT * FROM student";PreparedStatement ps = conn.prepareStatement(sql);// 执行sql语句,接收结果集ResultSet rs = ps.executeQuery();while (rs.next()) {System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + "\t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));}// 释放资源conn.close();ps.close();rs.close();System.out.println("使用之后连接池数量:" + dataSource.getSize());}
}

上面的代码是有问题的,因为最后释放了资源以后,通过查看使用后的连接池的数量发现没有归还操作,那连接池存在就没有意义了,连接池存在就是为了重复使用的。

连接池归还连接:

归还连接_继承:

通过打印连接对象,发现DriverManager获取的连接实现类是JDBC4Connection。

自定义一个类,继承JDBC4Connection这个类,定义连接对象和连接池容器对象的成员变量,通过有参构造对成员变量赋值,重写close()方法,将连接对象添加到池中
定义了子类完成了归还,但是DriverManager获取的还是JDBC4Connection这个对象,不是定义的子类,所以继承搞不了

归还连接_装饰设计模式:

自定义一个类,实现Connection接口,这样就和JDBC4Connection有相同的方法,重写close方法,剩余方法,只需要调用mysql驱动包的连接对象完成即可,但是这个设计模式需要重写很多的方法,比较麻烦

自定义类连接池:

package com.dataSource;import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;public class MyDataSource implements DataSource {// 定义集合容器,用于保存多个数据库连接对象private static final List<Connection> pool = Collections.synchronizedList(new ArrayList<>());// 静态代码块,生成10个数据库连接保存到集合中static {for (int i = 0; i < 10; i++) {Connection coon = JDBCUtils.getConnection();pool.add(coon);}}// 从连接池返回一个数据库连接@Overridepublic Connection getConnection() {if (pool.size() > 0) {// 从池中获取数据库连接Connection con = pool.remove(0);// 通过自定义连接对象进行包装MyConnection mycon = new MyConnection(con, pool);// 返回包装后的连接对象return mycon;} else {throw new RuntimeException("连接数量耗尽");}}/**定义getSize方法,获取连接池容器的大小*/public int getSize() {return pool.size();}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}
}

自定义连接类:

package com.dataSource;import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;/*自定义Connection类。通过装饰设计模式,实现和mysql驱动包中的Connection实现类相同的功能!实现步骤:1.定义一个类,实现Connection接口2.定义Connection连接对象和连接池容器对象的变量3.提供有参构造方法,接收连接对象和连接池对象,对变量赋值4.在close()方法中,完成连接的归还5.剩余方法,还是只需要调用mysql驱动包的连接对象完成即可*/public class MyConnection implements Connection {private Connection con;private List<Connection> pool;public MyConnection(Connection con, List<Connection> pool) {this.con = con;this.pool = pool;}@Overridepublic void close() throws SQLException {pool.add(con);}@Overridepublic Statement createStatement() throws SQLException {return con.createStatement();}@Overridepublic PreparedStatement prepareStatement(String sql) throws SQLException {return con.prepareStatement(sql);}@Overridepublic CallableStatement prepareCall(String sql) throws SQLException {return con.prepareCall(sql);}@Overridepublic String nativeSQL(String sql) throws SQLException {return con.nativeSQL(sql);}@Overridepublic void setAutoCommit(boolean autoCommit) throws SQLException {con.setAutoCommit(autoCommit);}@Overridepublic boolean getAutoCommit() throws SQLException {return con.getAutoCommit();}@Overridepublic void commit() throws SQLException {con.commit();}@Overridepublic void rollback() throws SQLException {con.rollback();}@Overridepublic boolean isClosed() throws SQLException {return con.isClosed();}@Overridepublic DatabaseMetaData getMetaData() throws SQLException {return con.getMetaData();}@Overridepublic void setReadOnly(boolean readOnly) throws SQLException {con.setReadOnly(readOnly);}@Overridepublic boolean isReadOnly() throws SQLException {return con.isReadOnly();}@Overridepublic void setCatalog(String catalog) throws SQLException {con.setCatalog(catalog);}@Overridepublic String getCatalog() throws SQLException {return con.getCatalog();}@Overridepublic void setTransactionIsolation(int level) throws SQLException {con.setTransactionIsolation(level);}@Overridepublic int getTransactionIsolation() throws SQLException {return con.getTransactionIsolation();}@Overridepublic SQLWarning getWarnings() throws SQLException {return con.getWarnings();}@Overridepublic void clearWarnings() throws SQLException {con.clearWarnings();}@Overridepublic Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {return con.createStatement(resultSetType,resultSetConcurrency);}@Overridepublic PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {return con.prepareStatement(sql,resultSetType,resultSetConcurrency);}@Overridepublic CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {return con.prepareCall(sql,resultSetType,resultSetConcurrency);}@Overridepublic Map<String, Class<?>> getTypeMap() throws SQLException {return con.getTypeMap();}@Overridepublic void setTypeMap(Map<String, Class<?>> map) throws SQLException {con.setTypeMap(map);}@Overridepublic void setHoldability(int holdability) throws SQLException {con.setHoldability(holdability);}@Overridepublic int getHoldability() throws SQLException {return con.getHoldability();}@Overridepublic Savepoint setSavepoint() throws SQLException {return con.setSavepoint();}@Overridepublic Savepoint setSavepoint(String name) throws SQLException {return con.setSavepoint(name);}@Overridepublic void rollback(Savepoint savepoint) throws SQLException {con.rollback(savepoint);}@Overridepublic void releaseSavepoint(Savepoint savepoint) throws SQLException {con.releaseSavepoint(savepoint);}@Overridepublic Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {return con.createStatement(resultSetType,resultSetConcurrency,resultSetHoldability);}@Overridepublic PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {return con.prepareStatement(sql,resultSetType,resultSetConcurrency,resultSetHoldability);}@Overridepublic CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {return con.prepareCall(sql,resultSetType,resultSetConcurrency,resultSetHoldability);}@Overridepublic PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {return con.prepareStatement(sql,autoGeneratedKeys);}@Overridepublic PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {return con.prepareStatement(sql,columnIndexes);}@Overridepublic PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {return con.prepareStatement(sql,columnNames);}@Overridepublic Clob createClob() throws SQLException {return con.createClob();}@Overridepublic Blob createBlob() throws SQLException {return con.createBlob();}@Overridepublic NClob createNClob() throws SQLException {return con.createNClob();}@Overridepublic SQLXML createSQLXML() throws SQLException {return con.createSQLXML();}@Overridepublic boolean isValid(int timeout) throws SQLException {return con.isValid(timeout);}@Overridepublic void setClientInfo(String name, String value) throws SQLClientInfoException {con.setClientInfo(name,value);}@Overridepublic void setClientInfo(Properties properties) throws SQLClientInfoException {con.setClientInfo(properties);}@Overridepublic String getClientInfo(String name) throws SQLException {return con.getClientInfo(name);}@Overridepublic Properties getClientInfo() throws SQLException {return con.getClientInfo();}@Overridepublic Array createArrayOf(String typeName, Object[] elements) throws SQLException {return con.createArrayOf(typeName,elements);}@Overridepublic Struct createStruct(String typeName, Object[] attributes) throws SQLException {return con.createStruct(typeName,attributes);}@Overridepublic void setSchema(String schema) throws SQLException {con.setSchema(schema);}@Overridepublic String getSchema() throws SQLException {return con.getSchema();}@Overridepublic void abort(Executor executor) throws SQLException {con.abort(executor);}@Overridepublic void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {con.setNetworkTimeout(executor,milliseconds);}@Overridepublic int getNetworkTimeout() throws SQLException {return con.getNetworkTimeout();}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return con.unwrap(iface);}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return con.isWrapperFor(iface);}
}
归还连接_适配器设计模式:

通过装饰设计模式有很多个需要实现的方法。这个时候就可以使用适配器设计模式了。提供一个适配器类,实现Connection接口,将所有功能进行实现(除了close方法)。自定义连接类只需要继承这个适配器类,重写需要改进的close()方法即可!

实现步骤:

  1. 定义一个适配器类,实现Connection接口
  2. 定义Connection连接对象的成员变量
  3. 通过有参构造方法完成对成员变量的赋值
  4. 重写所有方法(除close),调用mysql驱动包的连接对象完成
  5. 定义一个类,继承适配器父类
  6. 定义Connection连接对象和连接池容器对象的变量,通过有参构造进行赋值
  7. 重写close()方法中,完成归还连接
  8. 在自定义连接池中,将获取的连接对象通过自定义连接对象进行包装

适配器类:

package com.dataSource;import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;/* 定义一个适配器类,实现Connection接口定义Connection连接对象的成员变量通过有参构造方法完成对成员变量的赋值重写所有方法(除close),调用mysql驱动包的连接对象完成
*/public abstract class MyAdapter implements Connection {// 因为所有的方法还是要调用要有的连接对象所以需要有参把原有的对象接收进来// 一般适配器类都是抽象类,可以有抽象方法也可以有普通方法和构造private Connection con;public MyAdapter(Connection con) {this.con = con;}@Overridepublic Statement createStatement() throws SQLException {return con.createStatement();}@Overridepublic PreparedStatement prepareStatement(String sql) throws SQLException {return con.prepareStatement(sql);}@Overridepublic CallableStatement prepareCall(String sql) throws SQLException {return con.prepareCall(sql);}@Overridepublic String nativeSQL(String sql) throws SQLException {return con.nativeSQL(sql);}@Overridepublic void setAutoCommit(boolean autoCommit) throws SQLException {con.setAutoCommit(autoCommit);}@Overridepublic boolean getAutoCommit() throws SQLException {return con.getAutoCommit();}@Overridepublic void commit() throws SQLException {con.commit();}@Overridepublic void rollback() throws SQLException {con.rollback();}@Overridepublic boolean isClosed() throws SQLException {return con.isClosed();}@Overridepublic DatabaseMetaData getMetaData() throws SQLException {return con.getMetaData();}@Overridepublic void setReadOnly(boolean readOnly) throws SQLException {con.setReadOnly(readOnly);}@Overridepublic boolean isReadOnly() throws SQLException {return con.isReadOnly();}@Overridepublic void setCatalog(String catalog) throws SQLException {con.setCatalog(catalog);}@Overridepublic String getCatalog() throws SQLException {return con.getCatalog();}@Overridepublic void setTransactionIsolation(int level) throws SQLException {con.setTransactionIsolation(level);}@Overridepublic int getTransactionIsolation() throws SQLException {return con.getTransactionIsolation();}@Overridepublic SQLWarning getWarnings() throws SQLException {return con.getWarnings();}@Overridepublic void clearWarnings() throws SQLException {con.clearWarnings();}@Overridepublic Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {return con.createStatement(resultSetType, resultSetConcurrency);}@Overridepublic PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {return con.prepareStatement(sql, resultSetType, resultSetConcurrency);}@Overridepublic CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {return con.prepareCall(sql, resultSetType, resultSetConcurrency);}@Overridepublic Map<String, Class<?>> getTypeMap() throws SQLException {return con.getTypeMap();}@Overridepublic void setTypeMap(Map<String, Class<?>> map) throws SQLException {con.setTypeMap(map);}@Overridepublic void setHoldability(int holdability) throws SQLException {con.setHoldability(holdability);}@Overridepublic int getHoldability() throws SQLException {return con.getHoldability();}@Overridepublic Savepoint setSavepoint() throws SQLException {return con.setSavepoint();}@Overridepublic Savepoint setSavepoint(String name) throws SQLException {return con.setSavepoint(name);}@Overridepublic void rollback(Savepoint savepoint) throws SQLException {con.rollback(savepoint);}@Overridepublic void releaseSavepoint(Savepoint savepoint) throws SQLException {con.releaseSavepoint(savepoint);}@Overridepublic Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {return con.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);}@Overridepublic PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {return con.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);}@Overridepublic CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {return con.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);}@Overridepublic PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {return con.prepareStatement(sql, autoGeneratedKeys);}@Overridepublic PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {return con.prepareStatement(sql, columnIndexes);}@Overridepublic PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {return con.prepareStatement(sql, columnNames);}@Overridepublic Clob createClob() throws SQLException {return con.createClob();}@Overridepublic Blob createBlob() throws SQLException {return con.createBlob();}@Overridepublic NClob createNClob() throws SQLException {return con.createNClob();}@Overridepublic SQLXML createSQLXML() throws SQLException {return con.createSQLXML();}@Overridepublic boolean isValid(int timeout) throws SQLException {return con.isValid(timeout);}@Overridepublic void setClientInfo(String name, String value) throws SQLClientInfoException {con.setClientInfo(name, value);}@Overridepublic void setClientInfo(Properties properties) throws SQLClientInfoException {con.setClientInfo(properties);}@Overridepublic String getClientInfo(String name) throws SQLException {return con.getClientInfo(name);}@Overridepublic Properties getClientInfo() throws SQLException {return con.getClientInfo();}@Overridepublic Array createArrayOf(String typeName, Object[] elements) throws SQLException {return con.createArrayOf(typeName, elements);}@Overridepublic Struct createStruct(String typeName, Object[] attributes) throws SQLException {return con.createStruct(typeName, attributes);}@Overridepublic void setSchema(String schema) throws SQLException {con.setSchema(schema);}@Overridepublic String getSchema() throws SQLException {return con.getSchema();}@Overridepublic void abort(Executor executor) throws SQLException {con.abort(executor);}@Overridepublic void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {con.setNetworkTimeout(executor, milliseconds);}@Overridepublic int getNetworkTimeout() throws SQLException {return con.getNetworkTimeout();}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return con.unwrap(iface);}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return con.isWrapperFor(iface);}
}

继承适配器类:

public class MyConnection2 extends MyAdapter {private Connection con;private List<Connection> pool;public MyConnection2(Connection con, List<Connection> pool) {super(con);this.con = con;this.pool = pool;}@Overridepublic void close() throws SQLException {pool.add(con);}
}

自定义连接池类:

public class MyDataSource implements DataSource {// 定义集合容器,用于保存多个数据库连接对象private static final List<Connection> pool = Collections.synchronizedList(new ArrayList<>());// 静态代码块,生成10个数据库连接保存到集合中static {for (int i = 0; i < 10; i++) {Connection coon = JDBCUtils.getConnection();pool.add(coon);}}// 从连接池返回一个数据库连接@Overridepublic Connection getConnection() {if (pool.size() > 0) {// 从池中获取数据库连接Connection con = pool.remove(0);// 通过自定义连接对象进行包装MyConnection mycon = new MyConnection(con, pool);// 返回包装后的连接对象return mycon;} else {throw new RuntimeException("连接数量耗尽");}}/**定义getSize方法,获取连接池容器的大小*/public int getSize() {return pool.size();}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}

测试类:

public class DataSourceTest {public static void main(String[] args) throws SQLException {// 创建连接池对象MyDataSource dataSource = new MyDataSource();System.out.println("使用之前连接池数量:" + dataSource.getSize());// 通过连接池对象获取连接对象Connection conn = dataSource.getConnection();// 查看DriverManager连接的实现类System.out.println(conn.getClass());// 查询学生表的全部信息String sql = "SELECT * FROM student";PreparedStatement ps = conn.prepareStatement(sql);// 执行sql语句,接收结果集ResultSet rs = ps.executeQuery();while (rs.next()) {System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + "\t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));}// 释放资源conn.close();ps.close();rs.close();System.out.println("使用之后连接池数量:" + dataSource.getSize());}
}

适配器模式也可以实现,但是也很麻烦,说白了就是把装饰设计模式拆分了而已

连接池归还_动态代理:

经过适配器模式的改进,自定义连接类中的方法已经很简洁了。剩余所有的方法已经抽取到了适配器类中。但是适配器这个类还是我们自己编写的,也比较麻烦!所以可以使用动态代理的方式来改进。

自定义数据库连接池类:

public class MyDataSource implements DataSource{//定义集合容器,用于保存多个数据库连接对象private static List<Connection> pool = Collections.synchronizedList(new ArrayList<Connection>());//静态代码块,生成10个数据库连接保存到集合中static {for (int i = 0; i < 10; i++) {Connection con = JDBCUtils.getConnection();pool.add(con);}}//返回连接池的大小public int getSize() {return pool.size();}//动态代理方式@Overridepublic Connection getConnection() {if(pool.size() > 0) {//从池中获取数据库连接Connection con = pool.remove(0);Connection proxyCon = (Connection)Proxy.newProxyInstance(con.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {/*执行Connection实现类所有方法都会经过invoke如果是close方法,则将连接还回池中如果不是,直接执行实现类的原有方法*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if(method.getName().equals("close")) {pool.add(con);return null;}else {return method.invoke(con,args);}}});return proxyCon;}else {throw new RuntimeException("连接数量已用尽");}}
}
C3P0:

C3P0是一个开源的JDBC连接池,简化了很多步骤

使用步骤:

  1. 导入jar包
  2. 导入配置文件到src目录下
  3. 创建c3p0连接池对象
  4. 获取数据库连接进行使用 注意:C3p0的配置文件会自动加载,但是必须叫c3p0-config.xmlc3p0-config.properties

在这里插入图片描述
C3p0测试类:

public class C3p0Test {public static void main(String[] args) throws Exception {// 这里是空参的话,加载的就是默认的C3p0,如果指定名称就可以用自定义的DataSource dataSource = new ComboPooledDataSource();// 通过连接池对象获取数据库连接Connection con = dataSource.getConnection();// 查询学生表的全部信息String sql = "SELECT * FROM student";PreparedStatement ps = con.prepareStatement(sql);// 执行sql语句,接收结果集ResultSet rs = ps.executeQuery();while (rs.next()) {System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + "\t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));}// 释放资源con.close();ps.close();rs.close();}
}

测试连接池归还情况:

public class C3P0Test02 {public static void main(String[] args) throws Exception {DataSource dataSource = new ComboPooledDataSource();// 定的是10个连接池,如果是11=5个应该会在3秒以后去申请新的,然后报错for (int i = 0; i < 15; i++) {Connection con = dataSource.getConnection();System.out.println(i + "   " + con);// 执行到第六次的时候关闭,如果处理了close 地址值肯定是有两个重复的if (i == 6) {con.close();}}// 第6个的连接执行到的时候就关闭掉,可以看到打印结果第6、7次的地址值是一样的,有十一个地址值,说明是做了归还处理}
}

配置类:c3p0-config.xml

<c3p0-config><!-- 使用默认的配置读取连接池对象 --><default-config><!--  连接参数 --><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost/db2</property><property name="user">root</property><property name="password">itzhuzhu</property><!-- 连接池参数 --><!--初始化的连接数量--><property name="initialPoolSize">5</property><!--最大连接数量  初始化为5,最大10,意思就是默认给5个,不够再要,但是最多10个--><property name="maxPoolSize">10</property><!--超时时间 毫秒--><property name="checkoutTimeout">3000</property></default-config><!--这里是和上面一样的配置,但是c3p0默认的是上面这个,也可以自己加name,不指定的时候默认使用上面的--><named-config name="otherc3p0"> <!--  连接参数 --><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/db2</property><property name="user">root</property><property name="password">itzhuzhu</property><!-- 连接池参数 --><property name="initialPoolSize">5</property><property name="maxPoolSize">8</property><property name="checkoutTimeout">1000</property></named-config>
</c3p0-config>
Druid:

阿里开发的数据库连接池工具,不会自动加载配置文件,需要手动去读取,文件名称可以随意取,连接池也不会释放。

使用步骤:

  1. 导入jar包
  2. 编写配置文件,放在src目录下
  3. 通过Properties集合加载配置文件
  4. 通过Druid连接池工厂类获取数据库连接池对象
  5. 获取数据库连接,进行使用

工具类:

public class DataSourceUtils {//1.私有构造方法private DataSourceUtils() {}//2.定义DataSource数据源变量private static DataSource dataSource;//3.提供静态代码块,完成配置文件的加载和获取连接池对象static {try {//加载配置文件InputStream is = DataSourceUtils.class.getClassLoader().getResourceAsStream("druid.properties");Properties prop = new Properties();prop.load(is);//获取数据库连接池对象dataSource = DruidDataSourceFactory.createDataSource(prop);} catch (Exception e) {e.printStackTrace();}}//4.提供获取数据库连接的方法public static Connection getConnection() {Connection con = null;try {con = dataSource.getConnection();} catch (SQLException e) {e.printStackTrace();}return con;}//5.提供获取数据库连接池的方法public static DataSource getDataSource() {return dataSource;}//6.提供释放资源的方法public static void close(Connection con, Statement stat, ResultSet rs) {if (con != null) {try {con.close();} catch (SQLException e) {e.printStackTrace();}}if (stat != null) {try {stat.close();} catch (SQLException e) {e.printStackTrace();}}if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}}public static void close(Connection con, Statement stat) {close(con, stat, null);}
}

配置文件:

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost/db2
username=root
password=itzhuzhu#初始化连接数量
initialSize=5#最大连接数量
maxActive=10#超时时间
maxWait=3000

测试类:

public class DruidTest {public static void main(String[] args) throws Exception {Connection con = DataSourceUtils.getConnection();// 查询学生表的全部信息String sql = "SELECT * FROM student";PreparedStatement ps = con.prepareStatement(sql);// 执行sql语句,接收结果集ResultSet rs = ps.executeQuery();while (rs.next()) {System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + "\t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));}// 释放资源DataSourceUtils.close(con, ps, rs);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/572211.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Win Linux 双系统安装指南

双系统安装指南 环境说明 硬件&#xff1a;一块240G NVMe&#xff0c;一块240G SSD&#xff0c;一块2T的HDD。 系统&#xff1a;Linux Mint 18.2&#xff0c;Windows 10 Enterprise Version 1703 Update June 2017 分配&#xff1a;由于工作原因&#xff0c;我的主系统为Linux …

JDBC自定义框架

自定义JDBC框架&#xff1a; 定义必要的信息、获取数据库的连接、释放资源都是重复的代码&#xff0c;在操作JDBC时通常都是执行SQL语句就可以了&#xff0c;所以需要抽取出来一个模板类来封装一些方法&#xff08;Update、Query&#xff09;&#xff0c;专门执行增删改查的SQL…

SpingMVC 执行的流程

一&#xff1a;SpringMVC的开发步骤 ①&#xff1a;在web.xml文件中定义前端控制器DispatcherServlet来拦截用户请求。 由于Web应用是基于请求/响应结构的应用&#xff0c;所以不管哪个MVC Web框架&#xff0c;都需要在web.xml中配置该框架的核心Servlet或Filter&#xff0c;这…

UI 07 _ 导航视图控制器 与 属性传值

首先, 先创建三个VC. 完毕点击按钮, 进入下一页, 并可以返回. 要先把导航视图控制器创建出来. 在AppDelegate.m 文件里代码例如以下: #import "AppDelegate.h" #import "MainViewController.h" interface AppDelegate () endimplementation AppDelegate …

el表达式具体解释

引用内容百度百科(http://baike.baidu.com/view/1488964.htm) 參考百度百科&#xff0c;然后自己又加入了一部分自己感觉实用的东西&#xff0c;整理一下希望对大家有所帮助&#xff01;E L&#xff08;Expression Language&#xff09; 目的&#xff1a;为了使JSP写起来更加简…

MyBatis接口代理

MyBatis接口代理&#xff1a; 采用 Mybatis 的代理开发方式实现 DAO 层的开发&#xff0c;这种方式是目前的主流方式。Mapper 接口开发方法只需要程序员编写Mapper 接口&#xff08;相当于Dao 接口&#xff09;&#xff0c;由Mybatis 框架根据接口定义创建接口的动态代理对象&a…

编译OSG的FreeType插件时注意的问题

使用自己编译的freetype.lib&#xff0c;在编译osgdb_freetype插件项目时&#xff0c;报错LINK错误&#xff0c;找不到png的一堆函数 最简单的方式是不要使用PNG编译freetype。记住不要犯贱。 转载于:https://www.cnblogs.com/coolbear/p/7205906.html

openresty总结

协程 1.例如当获取的数据没有前后依赖关系时&#xff0c;可以使用ngx.thread.spawn和ngx.thread.wait同时从数据库不同的库、表或者不同来源&#xff08;mysql&#xff0c;redis等&#xff09;获取数据。https://github.com/openresty/lua-nginx-module#ngxthreadspawnhttps://…

PageHelper分页插件使用

分页插件PageHelper&#xff1a; MyBatis没有分页功能&#xff0c;需要手动编写LIMIT语句&#xff0c;可以使用第三方的插件来对功能进行扩展&#xff0c;分页助手PageHelper是将分页的复杂操作进行封装&#xff0c;使用简单的方式即可获得分页的相关数据 PageInfo&#xff1a;…

jquery插件开发通用框架

2017-07-24 更新&#xff1a;增加单例模式。 jquery插件开发框架代码&#xff1a; /** 插件编写说明&#xff1a;* 1、插件命名&#xff1a;jquery.[插件名].js&#xff0c;如jquery.plugin.js* 2、对象方法添加到jQuery.fn上&#xff0c;全局方法添加到jQuery对象本身上* 3、插…

Mybatis多表模型

多表模型&#xff1a; 多表模型分类 一对一&#xff1a;在任意一方建立外键&#xff0c;关联对方的主键。一对多&#xff1a;在多的一方建立外键&#xff0c;关联一的一方的主键。多对多&#xff1a;借助中间表&#xff0c;中间表至少两个字段&#xff0c;分别关联两张表的主键…

关于zkfc与zkserver频繁断开的问题

详见http://blog.csdn.net/dslztx/article/details/51596951转载于:https://www.cnblogs.com/roger888/p/7211625.html

高动态范围红外图像压缩

BF&DRC 近期看了一篇高动态范围红外图像压缩的文章&#xff0c;《New technique for the visualization of high dynamic range infrared images》.这篇文章主要利用双边滤波器把宽动态红外图像切割为基本图像和细节图像&#xff0c;再分别对基本图像和细节图像进行处理。对…

Mybatis构建sql语法

构建sql&#xff1a; 之前通过注解开发时&#xff0c;相关 SQL 语句都是自己直接拼写的。一些关键字写起来比较麻烦、而且容易出错。MyBatis 给我们提供了 org.apache.ibatis.jdbc.SQL 功能类&#xff0c;专门用于构建 SQL 语句 常用方法&#xff1a; 查询功能的实现&#xf…

Mqtt协议IOS端移植3

ServerMqFramework.h #import "MqttFramework.h"interface ServerMqFramework : MqttFramework/*** brief 得到模块控制器的句柄单例** param [in] N/A* param [out] N/A* return void* note*/(ServerMqFramework*)getMQttServerFrameInstance;- (int)callBusine…

java第三课,流程控制语句

流程控制语句条件语句&#xff1a;if语句&#xff1a;*if&#xff08;条件 boolean类型&#xff09;{ true }*if(boolean表达式){true}else&#xff5b;false结果&#xff5d;*多重 if else if(){}else if(){}else *嵌套ifSwitch语句&#xff1a;*switch(表达式){ case…

在cli命令行上显示当前数据库,以及查询表的行头信息

在$HIVE_HOME/conf/hive-site.xml文件下加入以下配置文件 <property><name>hive.cli.print.header</name><value>true</value><description>Whether to print the names of the columns in query output.</description> </proper…

两点之间最短路径:弗洛伊德算法

弗洛伊德算法是计算无向有权图中两点间最短路径的算法&#xff0c;复杂度为O(n^3)。其思路是将两点间距离分为过&#xff08;指定的&#xff09;第三点或是不过&#xff0c;然后取它们的最小值&#xff0c;如此循环就可以得到两点之间真正的最小值。 void floyd() {for (int k …

最常用的JavaScript 事件

JavaScript 事件&#xff1a; 事件指的就是当某些组件执行了某些操作后&#xff0c;会触发某些代码的执行。 更多事件&#xff1a;https://www.w3school.com.cn/jsref/dom_obj_event.asp 常用的事件&#xff1a; 属性触发时机onabort图像加载被中断onblur元素失去焦点onchange…

Codevs 1025 选菜

1025 选菜 时间限制: 1 s空间限制: 128000 KB题目等级 : 黄金 Gold题解题目描述 Description在小松宿舍楼下的不远处&#xff0c;有PK大学最不错的一个食堂——The Farmer’s Canteen&#xff08;NM食堂&#xff09;。由于该食堂的菜都很不错&#xff0c;价格也公道&#xff0c…