1、连接池
问题:连接池是什么,有什么用?
连接池:就是创建一个容器,用于装入多个connection对象,在使用连接对象时,从容器中获取一个connection,使用完成后,在将这个connection重新装入到容器中。这个容器就是连接池(DataSource),也叫做数据源。
我们可以通过连接池获取连接对象,
优点:节省连接与释放连接 性能消耗–连接池中连接起到复用的作用,提高程序性能
、、、、、、、、、、、、、、、、
自定义连接池
1、创建一个MyDataSource类,在这个类中创建一个LinkedList
2、在其构造方法中初始化List集合,并向其中装入5个Connection对象。
3、创建一个public Connection getConnection();从List集合中获取一个连接对象返回。
4、创建一个public void readd(Connection)这个方法是将使用完成后的Connection对象重新装入到List集合中。
代码问题:
(1)连接池的创建是有标准的
在javax.sql包下定义了一个接口DataSource
简单说,所有的连接池必须实现javax.sql.DataSource接口,我们的自定义连接池必须实现DataSource接口。
(2)我们操作时,要使用标准,怎样可以让con.close()他不是销毁,而是将其重新装入到连接池。
要解决这个问题,其本质就是将connection中的close()方法的行为改变。
怎么样可以改变一个方法的行为(对方法功能进行增强)
1、继承:必须能控制这个类的构造
2、装饰模式可以用模板类来避免实现全部方法
(1)装饰类与被装饰类要实现同一个接口或继承同一个父类
(2)在装饰类中持有一个呗装饰类引用
(3)对方法进行功能增强
3、动态代理
可以对行为增强
Proxy.newProxyInstance(ClassLoader,Class[],InvocationHandler);
结论:Connection对象如果是从连接池中获取到的,那么它的close方法的行为已经改变了,不在是销毁,而是重新装入到连接池。
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
1、连接池必须实现javax.sql.DataSource接口
2、要通过连接池获取连接对象 DataSource接口中有一个getConnection方法
3、将Connection重新装入到连接池 使用Connection的close()方法
2、开源连接池
1、c3p0(必会)
c3p0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。
目前使用它的开源项目有hibernate,spring等
c3p0与dbcp区别
dbcp没有自动回收空闲连接的功能
c3p0有自动回收空闲连接功能
C3p0连接池使用:
(1)导包
c3p0-0.9.1.2.jar
使用
1.手动
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass(“com.mysql.jdbc.Driver”);
cpds.setJdbcUrl(“jdbc:mysql:///day18”);
cpds.setUser(“root”);
cpds.setPassword(“abc”);
2.自动(使用配置文件)
c3p0的配置文件可以是properties也可以是xml.
c3p0的配置文件如果名称叫做 c3p0.properties or c3p0-config.xml 并且放置在classpath路径下(对于web应用就是classes目录)
那么c3p0会自动查找。
注意:我们其时只需要将配置文件放置在src下就可以。
使用:
ComboPooledDataSource cpds = new ComboPooledDataSource();
1
它会在指定的目录下查找指定名称的配置文件,并将其中内容加载。
2.dbcp(了解)
dbcp是apache的一个开源连接池。
要想使用DBCP连接池,要下载jar包
导入时要导入两个
commons-dbcp-1.4.jar
commons-pool-1.5.6.jar
关于dbcp连接池使用
1.手动配置(手动编码)
BasicDataSource bds = new BasicDataSource();
// 需要设置连接数据库最基本四个条件
bds.setDriverClassName("com.mysql.jdbc.Driver");
bds.setUrl("jdbc:mysql:///day18");
bds.setUsername("root");
bds.setPassword("abc");
// 得到一个Connection
Connection con = bds.getConnection();
2.自动配置(使用配置文件)
Properties props = new Properties();
FileInputStream fis = new FileInputStream(“D:\java1110\workspace\day18_2\src\dbcp.properties”);
props.load(fis);
DataSource ds = BasicDataSourceFactory.createDataSource(props);
关于c3p0一般有这么两种配置,一种是通过set方法进行配置,另一种是通过在同src目录下的c3p0-conflg.xml文件或者c3p0.properties文件进行相关的配置。
c3p0通过set方法进行配置
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
/**
* 配置DataSource
*/
public static void configDataSource(){
try {
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/zhanghanlun");
dataSource.setUser("zhanghanlun");
dataSource.setPassword("123456");
dataSource.setInitialPoolSize(3);
dataSource.setMaxPoolSize(10);
dataSource.setMinPoolSize(3);
dataSource.setAcquireIncrement(3);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}
/**
* 获取Connection连接
* @return
*/
public static Connection getConnection(){
Connection conn = null;
configDataSource();
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
c3p0通过c3p0-config.xml文件进行配置
关于通过配置文件进行配置的话,
这边需要把xml文件方法同src文件夹下,c3p0会扫描文件进行相关的配置。
在Maven依赖中要加入c3p0和mysql-connector-java依赖,版本号一定要写。
废话不多说,下面是c3p0-config.xml文件的代码
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<default-config>
<property name="user">zhanghanlun</property>
<property name="password">123456</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/zhanghanlun</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">3</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">2</property>
<property name="maxStatements">200</property>
</default-config>
<!-- 命名的配置,可以通过方法调用实现 -->
<named-config name="test">
<property name="user">zhanghanlun</property>
<property name="password">123456</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/zhanghanlun</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- 如果池中数据连接不够时一次增长多少个 -->
<property name="acquireIncrement">5</property>
<!-- 初始化数据库连接池时连接的数量 -->
<property name="initialPoolSize">20</property>
<!-- 数据库连接池中的最大的数据库连接数 -->
<property name="maxPoolSize">25</property>
<!-- 数据库连接池中的最小的数据库连接数 -->
<property name="minPoolSize">5</property>
</named-config>
</c3p0-config>
java代码对应如下:
//加载名字为“test”的配置文件
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("test");
/**
* 获取Connection连接
* @return
*/
public static Connection getConnection(){
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
是不是代码简洁了很多,所以在我们通常使用配置文件来创建数据库的连接池。
c3p0常用配置参数介绍
在前面的c3p0的相关配置中,我们看到了c3p0的配置参数,这里我们介绍几个常用的c3p0的配置参数
最基础的参数配置:
driverClass : 数据库驱动(比如mysql,或者oracle数据库的驱动)
jdbcUrl: jdbc数据库连接地址(例如jdbc:mysql://localhost:3306/zhanghanlun)
user:数据库用户名
password:和数据库用户名对应的数据库密码
基础的参数配置
参数 默认值 解释
initialPoolSize 3 连接池初始化时创建的连接数(介于maxPoolSize和minPoolSize之间)
maxPoolSize 15 连接池中拥有的最大连接数,如果获得新连接时会使连接总数超过这个值则不会再获取新连接,而是等待其他连接释放,所以这个值有可能会设计地很大
minPoolSize 3 连接池保持的最小连接数,后面的maxIdleTimeExcessConnections跟这个配合使用来减轻连接池的负载
acquireIncrement 3 连接池在无空闲连接可用时一次性创建的新数据库连接数
管理池大小和连接时间的配置
参数 默认值 解释
maxIdleTime 0 连接的最大空闲时间,如果超过这个时间,某个数据库连接还没有被使用,则会断开掉这个连接如果为0,则永远不会断开连接
maxConnectorAge 0 连接的最大绝对年龄,单位是秒,0表示绝对年龄无限大
maxIdleTimeExcessConnection 0 单位秒,为了减轻连接池的负载,当连接池经过数据访问高峰创建了很多连接,但是后面连接池不需要维护这么多连接,必须小于maxIdleTime.配置不为0,则将连接池的数量保持到minPoolSize
配置连接测试
参数 默认值 解释
automaticTestTable null 如果不为null,c3p0将生成指定名称的空表,使用该表来测试连接
connectionTesterClassName com.mchange.v2.c3p0.impl.DefaultConnectionTester -通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。
idleConnectionTestPeriod 0 每个几秒检查所有连接池中的空闲连接
preferredTestQuery null 定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意: 测试的表必须在初始数据源的时候就存在
testConnectionOnCheckin false 如果设为true那么在取得连接的同时将校验连接的有效性
testConnectionOnCheckout false 如果为true,在连接释放的同事将校验连接的有效性。
在这几个参数中,idleConnectionTestPeriod、testConnectionOnCheckout和testConnectuonOnCheckin控制什么时候连接将被校验检测。automaticTestTable、connectionTesterClassName和perferedTestQuery控制连接将怎么样被检测。
配置语句池
参数 默认值 解释
maxStatements 0 JDBC的标准参数,用以控制数据源内加载d的PreparedStatements数量
maxStatementsPerConnection 0 maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数
statementCacheNumDeferredCloseThreads 0 如果大于零,则语句池将延迟物理close()缓存语句直到其父连接未被任何客户端使用,或者在其内部(例如在测试中)由池本身使用。
配置数据库的中断恢复
参数 默认值 解释
acquireRetryAttempts 30 定义在从数据库获取新连接失败后重复尝试的次数
acquireRetryDelay 1000 两次连接间隔时间,单位毫秒
breakAfterAcquireFailure false 获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试 获取连接失败后该数据源将申明已断开并永久关闭
配置未解决的事务处理
参数 默认值 解释
autoCommitOnClose false 连接关闭时默认将所有未提交的操作回滚。如果为true,则未提交设置为待提交而不是回滚。
forceIgnoreUnresolvedTransactions false 官方文档建议这个不要设置为true
其他数据源配置
参数 默认值 解释
checkoutTimeout 0 当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒。
factoryClassLocation 0 指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可
numHelperThreads 3 c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能通过多线程实现多个操作同时被执行
DBUtils
DBUtils简化了JDBC的开发步骤,使得我们可以用更少量的代码实现连接数据库的功能。DBUtils下载地址
JavaBean组件
JavaBean是一个用于封装数据的类,在与数据库连接之中,JavaBean其的作用是将获取的数据库的记录封装到JavaBean中。特性如下:
- 需要实现接口:java.io.Serializable ,可以省略不写。
- 提供私有字段:private 类型 字段名;
- 提供getter/setter方法:
- 提供无参构造
DBUtils使用
DBUtils封装了JDBC的操作,核心功能如下:
Dbutils三个核心功能介绍
5. QueryRunner中提供对sql语句操作的API.
6. ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
7. DbUtils类是一个工具类,定义了关闭资源与事务处理的方法
QueryRunner核心类:
8. QueryRunner(DataSource ds) ;传入参数为连接池
9. update(String sql, Object… params) ,执行insert update delete操作
10. query(String sql, ResultSetHandler rsh, Object… params) ,执行 select操作
11. batch,批处理
// ArrayHandler处理类的使用,一条记录封装到数组object
public static void queryDemo01() throws SQLException{
// 1.创建QueryRunner对象
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.执行查询
Object[] objs = qr.query("select * from category where cid = ?", new ArrayHandler(), 1);
for(Object o: objs){ // object[]中保存了object对象
System.out.println(o);
}
}
// ArrayListHandler,多条记录封装到装有object数组的list集合
public static void queryDemo02() throws SQLException{
// 1.创建QueryRunner对象
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.执行查询
List<Object[]> objs = qr.query("select * from category ", new ArrayListHandler());
for (Object[] objects : objs) {
System.out.println(objects[0]+"\t"+objects[1]);
}
}
// BeanHandler处理类的使用,封装到JavaBean类
JavaBean
JavaBean就是一个类,在开发中常用语封装数据。具有如下特性
1.需要实现接口:java.io.Serializable ,通常实现接口这步骤省略了,不会影响程序。
2.提供私有字段:private 类型 字段名;
3.提供getter/setter方法:
4. 提供无参构造
public static void queryDemo03() throws SQLException{
// 1.创建QueryRunner对象
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.执行查询
String sql = "select * from category";
Category c = qr.query(sql, new BeanHandler<Category>(Category.class));
System.out.println(c);
}
// BeanListHandler
public static void queryDemo04() throws SQLException{
// 1.创建QueryRunner对象
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.执行查询
String sql = "select * from category";
List<Category> c = qr.query(sql, new BeanListHandler<Category>(Category.class));
for (Category category : c) {
System.out.println(category);
}
}
// ColumnListHandler处理类的使用
public static void queryDemo05() throws SQLException{
// 1.创建QueryRunner对象
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.执行查询
String sql = "select * from category";
List<Object> c = qr.query(sql, new ColumnListHandler<Object>("cname"));
System.out.println(c);
}
ScalarHandler: 将单个值封装、 例如select count(*),求内容的条数;
KeyedHandler:将多条记录封装到一个Map集合的Map集合中。并且外面的Map集合是可以指定的
// MapHandler处理类的使用
public static void queryDemo06() throws SQLException{
// 1.创建QueryRunner对象
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.执行查询
String sql = "select * from category";
Map<String, Object> map = qr.query(sql, new MapHandler());
// 3.
System.out.println(map);
}
// MapListHandler处理类的使用
public static void queryDemo07() throws SQLException{
// 1.创建QueryRunner对象
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.执行查询
String sql = "select * from category";
List<Map<String, Object>> maps = qr.query(sql, new MapListHandler());
// 3.List
System.out.println(maps);
}
// MapListHandler处理类的使用
public static void queryDemo08() throws SQLException{
// 1.创建QueryRunner对象
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.执行查询
String sql = "select count(*) from category";
Long count = qr.query(sql, new ScalarHandler<Long>());
// 3.List
System.out.println(count);
}
}