自定义连接池
用户每次请求都需要向数据库获得连接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。
Java为连接池实现提供了一个规范(接口),规范的写法,即实现DataSource接口
public class MyPool implements DataSource {
private static List<Connection> connections;
private static String driverClass;
private static String url;
private static String user;
private static String password;
static {
connections = Collections.synchronizedList(new LinkedList<>());
try {
//加载属性文件
InputStream is= MyPool.class.getClassLoader().getResourceAsStream("db.properties");
//创建集合
Properties properties=new Properties();
//从流中加载
properties.load(is);
//赋值
driverClass=properties.getProperty("driverClass");
url=properties.getProperty("url");
user=properties.getProperty("user");
password=properties.getProperty("password");
//注册驱动
Class.forName(driverClass);
//初始化元素
for (int i = 0; i < 5; i++) {
connections.add(DriverManager.getConnection(url, user, password));
}
System.out.println("连接池初始化完成");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Connection getConnection() throws SQLException {
synchronized (connections){
if(connections.size()>0){
Connection connection = connections.remove(0);
System.out.println("使用了"+connection.toString());
return connection;
}
}
return null;
}
//释放链接
public void release(Connection conn){
System.out.println("归还了:"+conn.toString());
connections.add(conn);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}
DBCP连接池
DBCP(DataBase connection pool),[数据库连接池]。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar。由于建立数据库连接是一个非常耗时的行为,所以通过连接池预先同数据库建立一些连接放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。
- 相应jar包 :
mysql驱动包,commons-dbcp.jar,commons-pool.jar,commons-logging.jar (日志支持)
- 硬编码使用DBCP:
所谓的硬编码方式就是在代码中添加配置。
public class DbUtils_DBCP {
private static BasicDataSource basicDataSource;
static {
//1.方式一:使用设置属性
basicDataSource = new BasicDataSource();
//1.1设置四个基本属性
basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
basicDataSource.setUrl("jdbc:mysql://localhost:3306/test");
basicDataSource.setUsername("root");
basicDataSource.setPassword("");
//1.2设置其他属性
//初始大小
basicDataSource.setInitialSize(10);
//最大大小
basicDataSource.setMaxTotal(50);
//最大空闲
basicDataSource.setMaxIdle(30);
//最小空闲
basicDataSource.setMinIdle(5);
//超时时间
basicDataSource.setMaxWaitMillis(5000);
}
//2.获取连接
public static Connection getConnection(){
try {
return basicDataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//3.释放资源
public static void closeAll(Connection conn, Statement stat, ResultSet rs){
try {
if (rs != null) {
rs.close();
}
if (stat != null) {
stat.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception{
for (int i = 0; i < 50; i++) {
Connection conn = DbUtils_DBCP.getConnection();
System.out.println(conn.toString());
conn.close();//并不会真正关闭连接,而是把对象放回连接池中
}
}
运行结果:
JDBC原始连接:
- 软编码使用DBCP:
所谓的软编码,就是在项目中添加配置文件,这样就不需要每次代码中添加配置!
文件名称:dbcp.properties 文件位置:src下
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxTotal=50
#<!-- 最大空闲连接 -->
maxIdle=30
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWaitMillis=5000
private static BasicDataSource basicDataSource;
static {
//2.方式二:使用配置文件
try {
Properties properties = new Properties();
InputStream is = Demo1.class.getClassLoader().getResourceAsStream("dbcp.properties");
//properties.load(new FileInputStream("src/info.properties"));
properties.load(is);
basicDataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
System.out.println("连接池初始化失败");
}
}
C3P0连接池
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
相应 jar 包:mysql驱动包、c3p0-0.9.1.2.jar、mchange-commons-java-0.2.11.jar
c3p0与dbcp区别:
1、dbcp没有自动回收空闲连接的功能,c3p0有自动回收空闲连接功能
2、dbcp需要手动加载配置文件,c3p0自动加载
- 硬编码使用C3P0:
private static ComboPooledDataSource dataSource;
static {
try {
dataSource = new ComboPooledDataSource();
//四个基本属性
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUser("root");
dataSource.setPassword("");
//其他属性
dataSource.setMaxPoolSize(50);
} catch (Exception e) {
e.printStackTrace();
}
}
运行结果:
- 软编码使用c3p0:
c3p0是在外部添加配置文件,工具直接进行应用,因为直接引用,所以要求固定的命名和文件位置
文件位置:src 文件命名:c3p0-config.xml / c3p0.properties
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<default-config>
<!-- 基本配置 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="user">root</property>
<property name="password"></property>
<!--扩展配置-->
<!-- 连接超过5秒报错-->
<property name="checkoutTimeout">5000</property>
<!--20秒检查空闲连接 -->
<property name="idleConnectionTestPeriod">20</property>
<!-- 初始大小 -->
<property name="initialPoolSize">10</property>
<!-- 每次增长的个数 -->
<property name="acquireIncrement">5</property>
<!-- 30秒不适用丢弃-->
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">50</property>
<property name="minPoolSize">10</property>
</default-config>
<!-- 命名的配置 -->
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mysql</property>
<property name="user">root</property>
<property name="password"></property>
<!-- 如果池中数据连接不够时一次增长多少个 -->
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">10</property>
<property name="maxPoolSize">50</property>
</named-config>
</c3p0-config>
XML 优先级高于 properties,XML 可以配置多个,properties 只可配置一个
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test
c3p0.user=root
c3p0.password=
c3p0.acquireIncrement=5
c3p0.initialPoolSize=10
c3p0.minPoolSize=10
c3p0.maxPoolSize=50
- Tips:
//1:c3p0的配置文件内部可以包含命名配置文件和默认配置文件,默认是选择默认配置,
//如果需要切换命名配置可以在创建c3p0连接池的时候填入命名即可。
public ComboPooledDataSource(String configName) {super(configName);}
//2:如果xml配置文件和属性文件都存在时,xml优先级高于属性文件
public class TestC3p0 {
public static void main(String[] args) throws Exception {
//创建ComboPooledDataSource对象使用默认配置
ComboPooledDataSource dataSource = new ComboPooledDataSource();
Connection connection = dataSource.getConnection();
Statement createStatement = connection.createStatement();
String sql = "select * from student;";
ResultSet resultSet = createStatement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getString(1));
}
resultSet.close();
createStatement.close();
connection.close();
}
}
Druid连接池
Druid 是目前比较流行的高性能的,分布式列存储的OLAP框架(具体来说是MOLAP)。它有如下几个特点:
一.亚秒级查询
druid提供了快速的聚合能力以及亚秒级的OLAP查询能力,多租户的设计,是面向用户分析应用的理想方式。
二.实时数据注入
druid支持流数据的注入,并提供了数据的事件驱动,保证在实时和离线环境下事件的实效性和统一性
三.可扩展的PB级存储
druid集群可以很方便的扩容到PB的数据量,每秒百万级别的数据注入。即便在加大数据规模的情况下,也能保证其时效性
四.多环境部署
druid既可以运行在商业的硬件上,也可以运行在云上。它可以从多种数据系统中注入数据,包括hadoop,spark,kafka,storm和samza等
五.丰富的社区
druid拥有丰富的社区,供大家学习
相关 jar 包:druid-1.1.5.jar
- 硬编码使用druid:
//声明连接池对象
private static DruidDataSource dataSource;
static{
dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("");
//初始大小
dataSource.setInitialSize(10);
//最大大小
dataSource.setMaxActive(50);
//最大空闲
dataSource.setMaxIdle(30);
//最小空闲
dataSource.setMinIdle(5);
//超时时间
dataSource.setMaxWait(5000);
public static void main(String[] args) throws Exception{
for (int i = 0; i < 50; i++) {
Connection conn = DbUtils_Druid.getConnection();
System.out.println(conn.toString());
// conn.close();//没有自动回收空闲连接功能
}
}
运行结果:
- 软编码使用druid:
druid.properties:
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=5000
//声明连接池对象
private static DruidDataSource dataSource;
static{
//实例化配置对象
Properties properties=new Properties();
try {
//加载配置文件内容
properties.load(DbUtils_Druid.class.getClassLoader().getResourceAsStream("druid.properties"));
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}