数据库连接池

传统方式获取 Connection 问题

1、每次向数据库建立连接时,都将 Connection 加载到内存,再验证 IP 地址、用户名、密码,频繁连接占用系统资源,服务器易崩溃

2、每次连接断开,若程序异常未能关闭,将导致数据库内存泄漏,导致数据库重启

3、不能控制创建连接数量

 

数据库连接池

1、预先在缓冲池放入一定数量连接,需要建立数据库连接时,从缓冲池中取出一个连接,使用完再放回

2、数据库连接池负责分配、管理、释放数据库连接,允许应用程序复用一个现有的数据库连接,而不是重建一个连接

3、当应用程序向连接池请求的连接数,超过最大连接数量时,这些请求将被加入到等待队列

4、JDBC 数据库连接池使用 javax.sql.DataSource 表示,该接口由第三方实现

5、种类

名称 说明
C3P0 速度相对慢,稳定性高
DBCP 速度相对 CP30 快,不稳定
Proxool 稳定性相对 C3P0 差,有监控连接池状态的功能
BoneCP 速度快
Druid 集 CP30、DBCP、Proxool 优点

 

Druid

1、DruidDataSource 配置

(1).xml 配置文件,通用配置

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 
     <property name="url" value="${jdbc_url}" />
     <property name="username" value="${jdbc_user}" />
     <property name="password" value="${jdbc_password}" />

     <property name="filters" value="stat" />

     <property name="maxActive" value="20" />
     <property name="initialSize" value="1" />
     <property name="maxWait" value="6000" />
     <property name="minIdle" value="1" />

     <property name="timeBetweenEvictionRunsMillis" value="60000" />
     <property name="minEvictableIdleTimeMillis" value="300000" />

     <property name="testWhileIdle" value="true" />
     <property name="testOnBorrow" value="false" />
     <property name="testOnReturn" value="false" />

     <property name="poolPreparedStatements" value="true" />
     <property name="maxOpenPreparedStatements" value="20" />

     <property name="asyncInit" value="true" />
 </bean>

(2)配置属性列表,DruidDataSource 配置兼容DBCP,但个别配置的语意有所区别

配置 缺省值 说明
name   配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。如果没有配置,将会生成一个名字,格式是:"DataSource-" + System.identityHashCode(this). 另外配置此属性至少在1.0.5版本中是不起作用的,强行设置name会出错
url   连接数据库的url,不同数据库不一样。例如:
mysql : jdbc:mysql://10.20.153.104:3306/druid2
oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username   连接数据库的用户名
password   连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter
driverClassName 根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName
initialSize 0 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
maxActive 8 最大连接池数量
maxIdle 8 已经不再使用,配置了也没效果
minIdle   最小连接池数量
maxWait   获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁
poolPreparedStatements false 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭
maxPoolPreparedStatementPerConnectionSize -1 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
validationQuery   用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用
validationQueryTimeout   单位:秒,检测连接是否有效的超时时间。底层调用jdbc Statement对象的void setQueryTimeout(int seconds)方法
testOnBorrow true 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testOnReturn false 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testWhileIdle false 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效
keepAlive false(1.0.28) 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作
timeBetweenEvictionRunsMillis 1分钟(1.0.14) 有两个含义:
1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。
2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
numTestsPerEvictionRun   不再使用,一个DruidDataSource只支持一个EvictionRun
minEvictableIdleTimeMillis   连接保持空闲而不被驱逐的最小时间
connectionInitSqls   物理连接初始化的时候执行的sql
exceptionSorter 根据dbType自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接
filters   属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
监控统计用的filter:stat
日志用的filter:log4j
防御sql注入的filter:wall
proxyFilters   类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系

(3)导入 .properties 配置文件,获取连接

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;

public class Program {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        //假设配置文件路径 src:\druid.properties
        properties.load(new FileInputStream("src:\\druid.properties"));
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        Connection connection = dataSource.getConnection();
    }
}

2、基于 Druid 的 JDBCUtils

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

public class JDBCUtilsByDruid {
    public static DataSource dataSource;

    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    //close把使用的Connection对象放回连接池
    public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (preparedStatement != null) {
                preparedStatement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

 

传统方式使用 ResultSet 的问题

1、ResultSet 与 Connection 关联,关闭连接后,不能继续使用 ResultSet

2、ResultSet 不利于数据管理,返回信息不方便

3、解决:DBUtils,JavaBean

 

JavaBean / POJO / Domain

1、解决 ResultSet 问题

2、表中的列与 JavaBean 中的属性存在映射(关联)关系

(1)数值型对应其包装类,因为 MySQL 所有类型都允许 NULL,而 Java 只有引用类型允许 NULL

(2)MySQL <-> Java:CHAR、VARCHAR <-> String,DATE <-> String / Date

3、DAO(Data Access Object):数据访问对象,DAO 操作 JavaBean,即具体表

 

DBUtils

1、commons-dbutils 是 Apache 组织提供的开源 JDBC 工具类库,对 JDBC 封装,极大简化 JDBC 编码的工作量

2、QueryRunner 类:封装 SQL 执行,线程安全,实现增删改查、批处理、查询

3、ResultSetHandler 接口:处理 java.sql.ResultSet,将数据按要求转换为另一种形式

4、实现 ResultSetHandler 接口的 JavaBean

(1)ArrayHandler:把结果集中的第一行数据转成对象数组

(2)ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中

(3)BeanHandler:将结果集中的第一行数据封装到一个对应 JavaBean 实例中

(4)BeanListHandler:将结果集中的每一行数据都封装到一个对应 JavaBean 实例中,存放到List里

(5)ColumnListHandler:将结果集中某一列的数据存放到 List 中

(6)KeyedHandler:将结果集中的每行数据都封装到 Map 里,再把这些 Map 再存到另一个 Map 里,其 key 为指定的 key

(7)MapHandler:将结果集中的第一行数据封装到一个 Map 里,key 是列名,value 是对应的值

(8)MapListHandler:将结果集中的每一行数据都封装到一个 Map 里,然后再存放到 List

 

DBUtils + Druid 的缺点

1、SQL 语句固定,不能通过参数传递,通用性低

2、对于 SELECT 操作,若有返回值,返回类型不确定,需要使用泛型

3、表的数量较多时,DAO 代码冗余复杂

 

BasicDAO

1、抽象各个 DAO 的共同操作

2、简化代码,提高维护性、可读性

3、通用类,专门与数据库交互,完成对数据表的 CRUD 操作

4、实现一张表对应一个具体 DAO

 

Service:业务层,不同 Service 调用单个 / 多个 DAO 完成综合操作

View:界面层,调用 Service,得到结果,显示数据

posted @   半条咸鱼  阅读(132)  评论(0编辑  收藏  举报
(评论功能已被禁用)
点击右上角即可分享
微信分享提示