前面我们已经知道了一些常用的JDBC操作,接下来我们继续深入,继续改进我们的DAO。
一、JDBC池链接
1、没有池的情况下:
总之就是不使用池的情况下:每次操作都需要进行连接数据库,连接中需要将Connection加载进内存中,验证用户名和密码等都需要话费时间。2、认识池
1、 池就是一种容纳对象的容器
2、 连接池就是保存数据库连接对象的容器
3、 在连接池中我们会预先创建一定数量的连接对象,当需要数据库连接的时候,只要从数据库连接池中取出一个,使用完毕之后就再放回去,这些连接对象是以一种循环队列来存放的,取的时候从头开始,放回的时候放在尾部。
4、 通过设置最大连接数量来防止系统无止尽的与数据库连接
5、 连接池中可以设置监听机制,用来测试连接的数量
连接池中的属性:
3、连接池的使用
1、 连接池是使用 java.sql.DataSource接口来表示连接池的
2、 DataSource和jdbc一样,也是只提供一个接口,由第三方组织来提供,所以连接池不同的厂家,有不同的连接池
4、详细步骤
DBCP的使用
以下代码就是获取数据库连接池,并获取连接对象。
二、配置信息
第一步 文件创建
1、项目目录下新建一个resource文件夹
2、编写db.properties文件
文件内容为:
// 记录配置信息
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mytest?rewriteBatchedStatements=true
username=root
password=zjj19970517
maxActive=8
为什么要使用配置文件?
第二步 文件读取
例子:
我们可以改写我们的utils类:(通过静态代码块执行获取连接池)
三、Druid使用
Druid是一个JDBC组件库,包括数据库连接池、SQL Parser等组件。DruidDataSource是最好的数据库连接池。
DBCP迁移到Druid
DruidDataSource的配置是兼容DBCP的。从DBCP迁移到DruidDataSource,只需要修改数据源的实现类就可以了。
四、DAO重构改进
1、抽取DML方法
数据查询语言DQL
数据操纵语言DML
数据定义语言DDL
数据控制语言DCL。
/**
* 更新操作公共方法
* @param sql 预编译sql语句
* @param params 参数数组
* @return
*/
public int _executeUpdate(String sql, Object...params) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 连接数据库
conn = JDBCUtils.getConnection();
// 创建预编译
ps = conn.prepareStatement(sql);
// 设置参数
for(int i= 0 ; i < params.length; i++) {
ps.setObject(i+1, params[i]);
}
// 执行更新
return ps.executeUpdate(); // 返回更新的行数
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, ps, null);
}
return -1; // 如果更新失败,返回-1
}
使用如下:
/**
* 存储学生
* @param stu
*/
public void save(Student stu) {
String sql = "insert into student (name, age) values (? , ?)";
this._executeUpdate(sql, stu.getName(), stu.getAge()); //直接调用
}
为了今后使用方便我们把_executeUpdate
方法抽取出来,放入一个CRUDTemplate
的模版类中。
package com.meils.jdbc.utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* CRUD操作模版
* @author apple
*
*/
public class CRUDTemplate {
/**
* 更新操作公共方法
* @param sql 预编译sql语句
* @param params 参数数组
* @return
*/
public static int _executeUpdate(String sql, Object...params) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 连接数据库
conn = JDBCUtils.getConnection();
// 创建预编译
ps = conn.prepareStatement(sql);
// 设置参数
for(int i= 0 ; i < params.length; i++) {
ps.setObject(i+1, params[i]);
}
// 执行更新
return ps.executeUpdate(); // 返回更新的行数
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, ps, null);
}
return -1; // 如果更新失败,返回-1
}
}
2、抽取DQL方法
第一步 新建handle处理层接口
新建一个包: com.meils.jdbc.handle
// IResultSetHandle.java
package com.meils.jdbc.handle;
import java.sql.ResultSet;
import java.util.List;
/**
* 结果集处理接口
* @author apple
*
*/
// 这里传入了类型,T为我们通过这个方法处理后要返回的类型
public interface IResultSetHandle<T>{
/**
* 处理结果集
* @param rs 传入结果集
* @return 返回List集合
*/
T handle(ResultSet rs);
}
第二步 实现接口类
在student的dao实现接口类中定义内部类
/**
* 结果集处理 实现类
* @author apple
*
*/
// 因为具体到某一个dao层的时候我们就知道了我们想要的类型了,所以传入<List<Student>>
class StuResultSetHandle implements IResultSetHandle <List<Student>>{
@Override
public List<Student> handle(ResultSet rs) {
List<Student> list = new ArrayList<Student>();
try {
while (rs.next()) {
Student stu = new Student();
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
stu.setId(rs.getInt("id"));
list.add(stu);
}
return list; // 返回集合
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
第三步 编写DQL模版方法
// CRUDTemplate.java
package com.meils.jdbc.utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.meils.jdbc.handle.IResultSetHandle;
/**
* CRUD操作模版
* @author apple
*
*/
public class CRUDTemplate {
/**
* 更新操作公共方法
* @param sql 预编译sql语句
* @param params 参数数组
* @return
*/
public static int _executeUpdate(String sql, Object...params) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 连接数据库
conn = JDBCUtils.getConnection();
// 创建预编译
ps = conn.prepareStatement(sql);
// 设置参数
for(int i= 0 ; i < params.length; i++) {
ps.setObject(i+1, params[i]);
}
// 执行更新
return ps.executeUpdate(); // 返回更新的行数
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, ps, null);
}
return -1; // 如果更新失败,返回-1
}
/**
* 查询 公共方法
* @param sql sql预编译语句
* @param rh 结果集处理的实现对象
* @param params 要给sql语句传入的参数
* @return 返回一个结果集
*/
// 这里我们也使用范型,因为我们这里要返回结果集处理方法处理完毕之后的集合,但是处理完毕的结果集我们并不知道是什么类型,因此我们需要通过范型来设置变化的类型
public static <T>T _executeQuery(String sql, IResultSetHandle<T> rh, Object... params) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
rs = ps.executeQuery();
return rh.handle(rs); // 处理结果集
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn, ps, rs);
}
return null;
}
}
第四步 使用如下
@Override
public Student findOne(int id) {
String sql = "select * from student where id = ?";
IResultSetHandle <List<Student>> result = new StuResultSetHandle();
List<Student> list = CRUDTemplate._executeQuery(sql,result,id);
return list.size() == 1 ? list.get(0) : null;
}
3、内省
(1)class类型
User u = User.class.newInstance(); // 使用class常见对象
User u1 = new User(); // 使用类名创建对象
(2) 内省
我们使用内省来查看一个JavaBean类内部的属性和get set方法。
package com.it666.jdbc.test;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import com.it666.jdbc.domain.User;
class ClassTest{
public Class c;
public ClassTest(Class c) {
this.c = c;
}
}
public class Test {
public static void main(String[] args) throws Exception {
/* ClassTest ct = new ClassTest(User.class);
User u = (User) ct.c.newInstance();*/
// 创建User 对象
User u = User.class.newInstance();
// 1获取beanInfo对象
BeanInfo beanInfo = Introspector.getBeanInfo(User.class,Object.class);
// 2获取beanInfo类的内部信息
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
// 获取属性名
//System.out.println(pd.getName());
// 获取get方法
///System.out.println(pd.getReadMethod());
// 获取set方法
System.out.println(pd.getWriteMethod());
// 调用方法
pd.getWriteMethod().invoke(u, "111");
}
// 使用User 对象的方法
System.out.println(u.getName());
System.out.println(u.getPwd());
}
}
4、使用内省封装通用的结果集处理器
- 处理单个结果集
package db.handle;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 结果集处理接口的实现类
* @author apple
*
* @param <T>
*
*/
public class BeanHandler<T> implements IResultSetHandle <T>{
public Class<T> classType;
public BeanHandler (Class<T> classType) {
this.classType = classType;
}
/**
* 处理结果集返回结果
* 返回一个对象
*/
@Override
public T handle(ResultSet rs) {
try {
if(rs.next()) {
try {
// 实例化一个对象
T obj = this.classType.newInstance();
// 获取BeanInfo 对象
BeanInfo bf = Introspector.getBeanInfo(this.classType, Object.class);
// 获取BeanClass 类的属性和方法
PropertyDescriptor[] pds = bf.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
Object val = rs.getObject(pd.getName());
//¸使用set方法,设置属性值
pd.getWriteMethod().invoke(obj, val);
}
return obj;
} catch(Exception e) {
e.printStackTrace();
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
- 处理多个结果集
package db.handle;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class BeanListHandler<T> implements IResultSetHandle<List<T>>{
private Class<T> classType;
public BeanListHandler(Class<T> classType) {
this.classType = classType;
}
/**
* 查询
* 返回集合
*/
@Override
public List<T> handle(ResultSet rs) {
List<T> list = new ArrayList<>();
try {
while(rs.next()) {
T obj = this.classType.newInstance();
BeanInfo bf = Introspector.getBeanInfo(this.classType,Object.class);
PropertyDescriptor[] pds = bf.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
Object val = rs.getObject(pd.getName());
pd.getWriteMethod().invoke(obj, val);
}
list.add(obj);
}
return list;
}catch (Exception e) {
e.printStackTrace();;
}
return null;
}
}
- 使用如下:
package db.dao.impl;
import java.util.List;
import db.dao.IStudentDao;
import db.domain.Student;
import db.handle.BeanHandler;
import db.handle.BeanListHandler;
import db.utils.CRUDTemplate;
public class StudentDaoImpl implements IStudentDao {
@Override
public int save(Student stu) {
String sql = "insert into student (name, age) values (? , ?)";
return CRUDTemplate._executeUpdate(sql, stu.getName(), stu.getAge());
}
@Override
public int delete(int id) {
String sql = "delete from student where pid = ?";
return CRUDTemplate._executeUpdate(sql, id);
}
@Override
public int update(int id, Student stu) {
String sql = "update student set name=?, age=? where pid =? ";
return CRUDTemplate._executeUpdate(sql, stu.getName(), stu.getAge(), id);
}
@Override
public Student findOne(int id) {
String sql = "select * from student where pid = ?";
return CRUDTemplate._executeQuery(sql, new BeanHandler<Student>(Student.class), id);
}
@Override
public List<Student> findAll() {
String sql = "select * from student ";
return CRUDTemplate._executeQuery(sql,new BeanListHandler<Student>(Student.class));
}
}