连接池:解决资源浪费,提高代码性能。
本小节目标:
使用DBCP,C3P0连接池完成基本数据库的操作。
使用DBUtils完成CRUD的操作。
数据库连接池的解决方案是:
当应用程序启动时,系统主动建立足够的数据库连接,并将这些连接组成一个连接池。每次应用程序请求数据库连接时,无须重新打开连接,而是从连接池中取出已有的连接使用,使用完后不再关闭数据库连接,而是直接将连接归还给连接池。通过使用连接池,将大大提高程序的运行效率。
数据库连接池是Connection 对象的工程。数据库连接池的常用参数如下。
a、数据库的初始连接数
b、连接池的最大连接数
c、连接池的最小连接数
d、连接池每次增加的容量
公共接口:javax.sql.DataSource。
常见的连接池:DBCP 、 C3P0 (主要)
自定义连接池代码实现改进(增强close方法):
自定义连接池中存在的严重问题,用户调用getConnection()获得连接后,必须使用release()方法进行连接的归还,如果用户调用conn.close()将连接真正的释放,连接池中将出现无连接可以。
方法增强的办法:
a、继承,子类继承父类,将父类的方法进行复写,从而进行增强。
使用前提:必须有父类,且存在继承关系。
b、装饰者设计模式,此设计模式专门用于增强方法。
使用前提:必须有接口
缺点:需要将接口的所有方法都实现
c、动态代理:在运行时动态的创建代理类,完成增强操作。与装饰者相似
使用前提:必须有接口
难点:需要反射技术
d、字节码增强,运行时创建目标类子类,从而进行增强
常见第三方框架:cglib 、javassist等。
连接池释放资源问题(WEB_10视频05自定义连接池代码实现改进(增强close方法)):
使用 c3p0 的话,也是 java.sql.Connection,只要是 JDBC 都是这个接口的对象!
使用完后必须 con.close() 掉,使用连接池的话,执行 con.close 并不会关闭与数据库的 TCP 连接,而是将连接还回到池中去,如果不 close 掉的话,这个连接将会一直被占用,直接连接池中的连接耗尽为止。
至于是如何做到 con.close 并不是真正意义上的关闭连接?而是直接将连接还回到池中去?
一般有两种方式:
一:使用装饰器模式,在装饰器构造中传入一个真正的 Connection,这个装饰器实现 Connection,使用构造 传入 Connection 委托重写所有方法,并改写 close 方法:
Java code
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public class ConnectionDecorator implements Connection { private Connection con = null; public ConnectionDecorator(Connection con) { this.con = con; } public void close() throws SQLException { // 重写! } public void commit() throws SQLException { this.con.commit(); } public Statement createStatement() throws SQLException { return this.con.createStatement(); } public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { return this.con.createStatement(resultSetType, resultSetConcurrency); } ...... } |
然后经过连接池控制的 Connection 对象都使用该装饰器进行包装
二:动态代理:
使用动态代理重新实现 close 方法,每个获得 Connection 是一个代理后的对象。
一个完善的连接池,其架构设计非常复杂,Connection#close 问题就是连接池诸多设计难点当中的一个。
总结:
关于学习MySql 以及JDBC方面的总结!
一、MySql
MySQL基本命令
SQL(全称)语句基础:DML 、 DDL 、 DCL 、 DQL
数据库约束
查询(单表、多表 左右连接等)
truncate 和 delete比较?
等等等
二、JDBC编程步骤
1、加载驱动
c3p0-config.xml
db.properties
2、获取连接
连接池概念
步骤 J3P0(XML)
3、DBUtils 完成CRUD (增删改查)
封装JDBC操作,简化JDBC操作
JavaBean组件(封装数据) 包:com.scalpet.domain
4、使用完连接池后:释放资源
得出结论,DBUtils在创建QueryRunner时传入dataSource对象每次在执行完之后都会自动关闭Connection连接对象~所以再也不用担心没有关闭对象而导致的问题了~如果没有传入dataSource的话 ·····需要手动关闭
三、练习
a、建立工程---java project
b、导入JDBC连接的jar包---jar包都添加在新文件夹lib下面
c、导入c3p0jar包
d、编写c3p0-config.xml文件
e、编写C3P0工具类---其核心工具类ComboPooledDataSource(命名配置、默认配置)---工具类都放在新建包com.scalpel.utils包下
f、编写JavaBean组件User----组件在新建包com.scalpel.domain包下
g、导入DBUtils的jar包
h、编写DBUtils的测试java类
代码实现:
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web</property>
<property name="user">root</property>
<property name="password">12345678</property>
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<named-config name="scalpel">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web</property>
<property name="user">root</property>
<property name="password">12345678</property>
</named-config>
</c3p0-config>
C3P0Utils工具类:
package com.scalpel.jdbc.utils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Utils {
//使用命名配置
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("scalpel");
/*
* 获得数据源(连接池)
*/
public static DataSource getDataSource()
{
return dataSource;
}
/*
* 获得连接
*/
public static Connection getConnection()
{
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException();
}
}
}
userbean组件类:
package com.scalpel.domain;
public class User {
private int id;
private String name;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
连接测试类:
package com.scalpel.jdbc.link;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.Test;
import com.scalpel.domain.User;
import com.scalpel.jdbc.utils.C3P0Utils;
public class LinkJDBC {
/*
* 添加用户
*/
@Test
public void AddUser() {
try {
// 1.连接数据源连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.编写sql语句
String sql = "insert into user values( ?, ?, null )";
// 3.添加params参数
Object[] params = { "ctxixi", "123" };
// 4.执行sql语句
int rows = qr.update(sql, params);
// 5.判断是否执行成功
if (rows > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* 查询用户,使用BeanListHandler
*/
@Test
public void QueryAllUserInf()
{
try {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from user";
List<User> queryUser = qr.query(sql, new BeanListHandler<User>(User.class));
for (User user : queryUser)
{
System.out.println(user.getId() +"、" + user.getName() + " : " + user.getPassword());
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}