JDBC 高级
一. 数据库连接池的概念
数据库连接池: 用来分配,管理和释放数据库连接,允许程序重复使用一个现有的数据库连接,而不是再重新建立一个,能明显提高对数据库操作的性能
作用: 避免重复创建连接,提升程序的执行效率
二.开源数据库连接池
**C3P0**: 配置文件会自动加载,但是必须f放在src文件夹下,名字必须叫c3p0-config.xml或c3p0-config.properties
-
导包 2. 配置信息 3. 获取连接
…后面跟jdbc入门一样
package C3P0_Demo1; import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet;
import java.sql.SQLException;
public class Demo1 {
public static void main(String[] args) {
//获取对象
DataSource ds = new ComboPooledDataSource();
try {
//获取连接对象
Connection con = ds.getConnection();
//获取预编译执行对象
PreparedStatement sta = con.prepareStatement(“select * from student”);
//获取ResultSet 结果集对象
ResultSet res = sta.executeQuery();
while (res.next()) {
System.out.print(res.getInt(“sid”));
System.out.print(res.getString(“NAME”));
System.out.print(res.getInt(“age”));
System.out.println(" ");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
**Druid:**
不会自动加载配置文件,需要我们手动加载,名字就可以我们自己定义.
```java
package Druid_Demo1;
import Utils.DataSourceUtils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
public class Demo1 {
public static void main(String[] args) {
Connection con = null;
PreparedStatement sta = null;
ResultSet res = null;
try {
// 通过DataSourceUtils 工具类获取连接对象
con = DataSourceUtils.getCon();
sta = con.prepareStatement("select * from student");
res = sta.executeQuery();
while (res.next()) {
System.out.print(res.getInt("sid"));
System.out.print(res.getString("NAME"));
System.out.print(res.getInt("age"));
System.out.println(" ");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DataSourceUtils.close(con, sta, res);
}
}
}
```
**数据库连接池工具类**
目的: 简化(封装) DataSource 的创建步骤
一个程序只需要维护一个DataSource
步骤: 私有工具类的构造方法
静态代码块中实现DataSource 的初始化
加载配合文件
创建DataSource
提供获取Connection 的方法
释放资源
```java
package Utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
public class DataSourceUtils {
//私有构造方法,
private DataSourceUtils() {
}
//定义数据库连接池
private static DataSource ds;
static {
//注意: 在读取src文件下的源文件时:
InputStream in = DataSourceUtils.class.getClassLoader().getResourceAsStream("路径名");
// 在读取web文件下的源文件时:
InputStream in = this.getServletContext().getResourceAsStream("路径名")
//通过类加载器动态获取输入流
InputStream in = DataSourceUtils.class.getClassLoader().getResourceAsStream("druid.properties");
Properties p = new Properties();
try {
p.load(in);
ds = DruidDataSourceFactory.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
//定义获取连接池对象的方法
public static DataSource getDs() {
return ds;
}
//定义获取连接对象的方法
public static Connection getCon() {
Connection con = null;
try {
con = ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
//关闭资源的方法
public static void close(Connection con, PreparedStatement sta, ResultSet res) {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (sta != null) {
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (res != null) {
try {
res.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Connection con, PreparedStatement sta) {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (sta != null) {
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
```
#### 三. JDBC 自定义框架
**背景:** 封装一些方法,将之前那些重复的操作,抽取到模板类中,能大大简化使用步骤
**源信息:** 代表当前数据库标的结构信息(字段名称以及数据类型).
##### 框架的编写:
```java
/*
* JDBC框架类
* */
public class JDBCTemplate {
//1.定义参数变量(数据源、连接对象、执行者对象、结果集对象)
private DataSource ds;
private Connection con;
private PreparedStatement sta;
private ResultSet res;
// 构造方法.给DataSource 赋值
public JDBCTemplate(DataSource ds) {
this.ds = ds;
}
/*
* 增删改的操作
* */
public int update(String sql, Object... obj) {
//定义变量,表示操作的行数
int result = 0;
sta = getSta(sql, obj);
//获取ResultSrt 对象
try {
result = sta.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result;
}
/*
* 定义一个方法,用来获取执行者对象
* */
public PreparedStatement getSta(String sql, Object... obj) {
try {
//获取连接对象
con = ds.getConnection();
//获取执行对象
sta = con.prepareStatement(sql);
//通过执行对象动态获取参数的源信息对象
ParameterMetaData parameterMetaData = sta.getParameterMetaData();
//通过源信息对象获取参数共有多少列
int parameterCount = parameterMetaData.getParameterCount();
//判断获取到的列数和sql语句要预编译的参数个数是否相等,相等则说明获取正确
if (obj.length == parameterCount) {
//给sql的参数占位符赋值
for (int i = 0; i < obj.length; i++) {
sta.setObject(i + 1, obj[i]);
}
} else {
//参数个数不匹配这说明获取到的数据有误
throw new RuntimeException("参数个数不匹配");
}
} catch (Exception e) {
e.printStackTrace();
}
return sta;
}
/*
* 查询数据,返回一个对象
* */
public <T> T findQuery(String sql, ResultSetHandler<T> rsh, Object... obj) {
T handler = null;
//获取执行者对象
PreparedStatement sta = getSta(sql, obj);
try {
ResultSet res = sta.executeQuery();
handler = rsh.handler(res);
} catch (SQLException e) {
e.printStackTrace();
}
return handler;
}
}
/*
用于处理结果集方式的接口(策略者模式)
*/
public interface ResultSetHandler<T> {
<T> T handler(ResultSet res);
}
/*
实现类:用于将查询到的一条记录,封装为指定对象并返回
*/
public class BeanHandler<T> implements ResultSetHandler<T> {
//定义Class 对象,用来确定对象属性
//以学生对对象为例, Student.class 获取到的就是学生对象的 calss 对象.可以通过反射直接new 对象
//Class<Student> studentClass = Student.class;
private Class<T> beanClass;
//定义构造方法,给beanClass 赋值
public BeanHandler(Class<T> beanClass) {
this.beanClass = beanClass;
}
//重写方法,用于将一条记录封装成一个自定义对象
@Override
public T handler(ResultSet res) {
//定义自定义变量类型
T bean = null;
try {
//创建对象
bean = beanClass.newInstance();//Student stu=studentClass.newInstance();
//判resultSet 是否有数据
if (res.next()) {
//获取结果源信息对象
ResultSetMetaData metaData = res.getMetaData();
//通过结果源信息对象获取结果集中的参数个数
int count = metaData.getColumnCount();
//循环列数
for (int i = 1; i <= count; i++) {
//获取字段名
String catalogName = metaData.getColumnName(i);
//获取对应的数据
Object object = res.getObject(catalogName);
//创建属性描述器对象,将获取到的值通过该对象的set方法进行赋值
PropertyDescriptor pd = new PropertyDescriptor(catalogName.toLowerCase(), beanClass);
//获取set方法
Method writeMethod = pd.getWriteMethod();
//执行set方法,给成员变量赋值
writeMethod.invoke(bean, object);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
/*
测试类
*/
@Test
public void findQuery() {
String sql = "select * from student where sid=?";
Student stu= jdbcTemplate.findQuery(sql, new BeanHandler<Student>(Student.class),1);
System.out.println(stu);
// Class<Student> studentClass = Student.class;
// Student student = studentClass.newInstance();
}