JavaWeb数据库开发知识总结(jdbc进阶)
1. JDBC开发的步骤
JDBC开发遵循以下步骤:
1. 导入JDBC的jar包,并添加至buildPath路径;
2. 加载驱动类(Driver类);
3. 获取数据库连接(Connection类);
4. 获取执行SQL语句的对象(Statement或PreparedStatement类);
5. 获取SQL语句执行的结果集对象(ResultSet对象);
6. 释放资源(Connection,Statement或PreparedStatement,ResultSet资源释放).
JDBC开发过程中数据库连接的处理及获取结果集对象处理较为常用和重要,则需要针对原始的数据库连接和结果集对象的处理优化.即将开发步骤的第3步和第5步进行优化.
针对数据库连接的优化是模仿线程池技术采用数据库连接池技术,同时也将加载驱动类进行了同步的封装.
针对数据库查询结果集的处理优化是采用对结果集进行封装的技术(DbUtils工具类),同时对执行SQL语句的对象进行了封装处理.
2. 数据库连接池
数据库连接对象的创建和销毁会消耗资源,为避免频繁的重复此操作,可以模仿线程池的原理设置数据库连接池提高效率.
数据库连接池原理是预先创建一批数据库连接对象,然后需要使用时直接从连接池进行获取,不再进行创建,使用完后不关闭,而是将使用完的连接对象归还到连接池中.
实现数据库连接池需要注意的问题:数据库连接对象的存储和回收.
2.1. 实现自定义数据库连接池
JDK提供数据库连接池的接口DataSource.
2.1.1 实现数据库连接池的思想
自定义类实现数据库连接池DataSource接口,在该类中定义集合用于存储连接对象,重写DataSource的getConnection()方法,在该方法中返回Connection对象,使用自定义方法将使用完的Connection对象再返回到数据库连接池中.代码实现如下:
/**
* 数据库连接池对象
*/
public class My_DataSource implements DataSource {
// 定义存储连接的集合
private List<Connection> connList = new ArrayList<Connection>();
// 通过构造方法初始化连接集合,数量为3个
public My_DataSource(){
for (int i = 0; i < 3; i++) {
// 通过JDBCUtils工具类获取Connection连接对象
Connection conn = JDBCUtils.getConnection();
// 将Connection对象添加到集合中
connList.add(conn);
}
}
// 重写DataSource的getConnection方法,返回的是此连接池中预先定义好的Connection对象
@Override
public Connection getConnection() throws SQLException {
// 返回数据库连接
if(connList.size() <= 0) {
// 当连接集合中连接数量少于0时,继续创建一批连接对象
for (int i = 0; i < 3; i++) {
Connection conn = JDBCUtils.getConnection();
connList.add(conn);
}
}
// 每次返回连接池中第一个,移除集合中第一个对象
Connection conn = connList.remove(0);
return conn;
}
// 自定义归还数据库连接对象的方法,将使用完的连接对象再添加回集合中
public void returnConnection(Connection conn) {
connList.add(conn);
}
...DataSource的其他方法省略
}
上述实现数据库连接池的弊端:
在上述的实现思想中将数据库连接对象返回到连接池中时,使用的是自定义方法归还,这种实现方式不符合面向接口编程的原则,并且使用自定义方法归还连接对象,增加了该连接池类的使用成本.
2.1.2 实现数据库连接池的另一种思想
使用DataSource的接口的获取的是Connection对象,可以将Connection对象的close()方法原有的关闭连接的功能改变为归还该连接对象到数据库连接池,该思想良好的遵循面向接口编程,并且没有增加新的方法.
增强或改变一个方法的功能可用的实现方式:
使用继承的方式:
继承父类的方法,可以进行父类方法的重写来增强父类方法的功能;
要求:子类必须能够控制父类的构造方法,才能使用继承(必须知道明确的父类及父类能被继承并且要增强的方法可以被重写).
装饰者设计模式:
将已有的类进行包装,将其中某些方法进行增强;
要求:包装对象和被包装的对象有实现的相同接口;包装对象中有被包装对象的引用.
缺点:如果接口的方法比较多,增强其中的某个方法.其他的功能的方法需要使用被包装对象去调用原有的方法.
动态代理的方式:
要求:需要增强的方法所属的类有实现的接口.
由于使用的mysql数据库提供的JDBC的jar包中实现的Connection接口类无法找到,无法使用继承的方式进行close方法功能的改造,则可以使用装饰者模式和动态代理的方式实现功能的改造,此处使用装饰者模式进行原始的Connection接口的包装;使用自定义类包装Connection接口中的close()方法,在获取数据库连接池中的连接对象时,将原始的Connection对象进行包装再返给调用者,则在调用者归还连接对象调用close方法时会调用被包装过的close方法,将连接对象归还到连接池中, 代码如下:
/**
* 原始的connection类的包装类
* 重写里面的close方法,将close功能改为将连接不进行销毁,将连接归还到连接池
*/
public class My_Connection implements Connection {
// 获得被包装对象的引用
private Connection conn;
// 获取连接池中的存储连接对象的集合对象,方便将使用完毕的Connection对象再添加到集合中
private List<Connection> connList;
// 通过构造方法获取被包装类的引用和连接对象存储的集合对象
public My_Connection(Connection conn,List<Connection> connList) {
this.conn = conn;
this.connList = connList;
}
// 重写Connection接口中的close方法
@Override
public void close() throws SQLException {
// 改造Connection的方法,将连接归还到连接池
connList.add(conn);
}
...Connection接口中其他方法通过conn对象调用原有的方法
}
/**
* 数据库连接池对象
*/
public class My_DataSource implements DataSource {
// 定义存储连接的集合
private List<Connection> connList = new ArrayList<Connection>();
// 通过构造方法初始化连接集合,数量为3个
public My_DataSource(){
for (int i = 0; i < 3; i++) {
Connection conn = JDBCUtils.getConnection();
connList.add(conn);
}
}
// 重写DataSource接口中的getConnection方法
@Override
public Connection getConnection() throws SQLException {
// 返回数据库连接
if(connList.size() <= 0) {
// 当连接集合中连接数量少于0时,重新生成
for (int i = 0; i < 3; i++) {
Connection conn = JDBCUtils.getConnection();
connList.add(conn);
}
}
// 每次返回连接池中第一个,并冲集合中移除
Connection conn = c