自定义JDBC框架
- 使用JDBC过程中有大量的重复代码, 核心功能仅仅执行一条SQL语句, 所以可以抽取一个JDBC模板类, 来封装一些方法(update query).
- 专门帮我们执行增删改查SQL语句. 将之前那些重复的操作, 都抽取到模板类中的方法里, 就能大简化使用步骤
源信息
- DataeBaseMetaData: 数据库的源信息
- java.sql.DataBaseMetaData 封装了整个数据库的综合信息
- 例如 String getDatabaseProductName(): 获取数据库产品的名称
- 例如int getDatabaseProductVersion: 获取数据库产品的版本号
- ParameterMetaData: 参数源信息
- java.sql.ParameterMetaData 封装的是预编译执行者对象中每个参数的类型和属性, 这个对象可以通过预编译执行者对象中的getParameterMetaData()方法来获取
- int getParameterCount() 用于获取SQL语句中的参数个数
- ResultSetMetaData: 结果集的源信息
- java.sql.ResultSetMetaData: 封装的是结果集对象中列的类型和属性, 这个对象可以通过结果集对象中的getMetaData()方法来获取
- int getColumnCount() 用于获取列的总数, String getColumnName(int i)用于获取列名
package com.test005;
import com.lizicai.utils.DataSourceUtils;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.*;
public class JDBCTemplate {
// 1. 定义参数变量(数据源, 连接对象, 执行者对象, 结果集对象
private DataSource dataSource;
private Connection con;
private PreparedStatement pst;
private ResultSet rs;
// 2. 通过有参构造为数据源赋值
public JDBCTemplate(DataSource dataSource){
this.dataSource = dataSource;
}
// 3. 定义update方法, 参数 sql语句 sql语句中的参数
public int update(String sql, Object... objs){
int result = 0;
try {
con = dataSource.getConnection();
pst = con.prepareStatement(sql);
ParameterMetaData parameterMetaData = pst.getParameterMetaData();
int count = parameterMetaData.getParameterCount();
if( count != objs.length){
throw new RuntimeException("参数个数不匹配");
}
for(int i=0; i< objs.length;i++){
pst.setObject(i+1,objs[i]);
}
result = pst.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
DataSourceUtils.close(con, pst);
}
return result;
}
}
package com.test005;
import com.lizicai.utils.DataSourceUtils;
import org.junit.Test;
public class JDBCTemplateTest1 {
private JDBCTemplate template = new JDBCTemplate(DataSourceUtils.getDataSource());
@Test
public void insert(){
String sql = "INSERT INTO student VALUES (?,?,?,?)";
Object[] params = {5,"周七",27,"1997-07-07"};
int result = template.update(sql, params);
if(result != 0){
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
}
@Test
public void update(){
String sql = "UPDATE student SET age=? WHERE name=?";
Object[] params = {37,"周七"};
int result = template.update(sql, params);
System.out.println(result);
}
@Test
public void delete(){
String sql = "DELETE FROM student where name=?";
Object[] params = {"周七"};
int result = template.update(sql, params);
System.out.println(result);
}
}
查询功能-框架编写
-
查询一条记录并封装对象的方法: queryForObject()
-
查询多条记录并封装集合的方法: queryForList()
-
查询聚合函数并返回单条数据的方法: queryForScalar()
-
实体类的编写
- 定义一个类, 提供一些成员变量( 成员变量的数据类型和表中的列保持一致)
package com.test005.domain;
import java.util.Date;
public class Student {
private Integer sid;
private String name;
private Integer age;
private Date birthday;
// get set constructor 略
}
package com.test005.handler;
import java.sql.ResultSet;
public interface ResultSetHandler<T> {
<T> T handler(ResultSet rs);
}
package com.test005.handler;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
// 1. 定义一个类, 实现ResultSetHandler 接口
public class BeanHandler<T> implements ResultSetHandler<T> {
// 2. 定义Class对象类型变量
private Class<T> beanClass;
// 3. 通过有参构造为变量赋值
public BeanHandler(Class<T> beanClass){
this.beanClass = beanClass;
}
// 4. 重写handler方法, 用于将一条记录封装到自定义对象中
@Override
public T handler(ResultSet rs) {
// 5. 声明自定义对象类型
T bean = null;
try {
// 6. 创建传递参数的对象, 为自定义对象赋值
bean = beanClass.newInstance();
// 7. 判断结果集中是否有数据
if(rs.next()){
// 8. 通过结果集对象获取结果集源信息的对象
ResultSetMetaData metaData = rs.getMetaData();
// 9. 通过结果集源信息对象获取列数
int count = metaData.getColumnCount();
// 10. 通过循环遍历列数
for(int i=1;i<= count;i++){
// 11. 通过结果集源信息对象获取列名
String columnName = metaData.getColumnName(i);
// 12. 通过列名获取该列的数据
Object value = rs.getObject(columnName);
// 13. 创建属性描述器对象, 将获取到的值通过该对象的set方法进行赋值
PropertyDescriptor pd = new PropertyDescriptor
(columnName.toLowerCase(), beanClass);
Method writeMethod = pd.getWriteMethod();
writeMethod.invoke(bean, value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
// 14. 返回封装好的对象
return bean;
}
}
public <T> T queryForObject(String sql, ResultSetHandler<T> rsh, Object...objs){
T obj = null;
try {
con = dataSource.getConnection();
pst = con.prepareStatement(sql);
ParameterMetaData parameterMetaData = pst.getParameterMetaData();
int count = parameterMetaData.getParameterCount();
if( count != objs.length){
throw new RuntimeException("参数个数不匹配");
}
for(int i=0; i< objs.length;i++){
pst.setObject(i+1,objs[i]);
}
rs = pst.executeQuery();
obj = rsh.handler(rs);
} catch (Exception e) {
e.printStackTrace();
} finally {
DataSourceUtils.close(con, pst);
}
return obj;
}
@Test
public void queryForObject(){
String sql = "SELECT * FROM student WHERE sid=?";
Student stu = template.queryForObject(sql, new BeanHandler<>(Student.class), 1);
System.out.println(stu);
}
查询列表
package com.test005.handler;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
// 1. 定义一个类, 实现ResultSetHandler 接口
public class BeanListHandler<T> implements ResultSetHandler<T> {
// 2. 定义Class对象类型变量
private Class<T> beanClass;
// 3. 通过有参构造为变量赋值
public BeanListHandler(Class<T> beanClass){
this.beanClass = beanClass;
}
// 4. 重写handler方法, 用于将一条记录封装到自定义对象中
@Override
public List<T> handler(ResultSet rs) {
// 5. 创建集合对象
List<T> beanList = new ArrayList<>();
try {
// 6. 循环判断是否有值
while (rs.next()){
// 7. 创建传递参数的对象, 为自定义对象赋值
T bean = beanClass.newInstance();
// 8. 通过结果集对象获取结果集源信息的对象
ResultSetMetaData metaData = rs.getMetaData();
// 9. 通过结果集源信息对象获取列数
int count = metaData.getColumnCount();
// 10. 通过循环遍历列数
for(int i=1;i<= count;i++){
// 11. 通过结果集源信息对象获取列名
String columnName = metaData.getColumnName(i);
// 12. 通过列名获取该列的数据
Object value = rs.getObject(columnName);
// 13. 创建属性描述器对象, 将获取到的值通过该对象的set方法进行赋值
PropertyDescriptor pd = new PropertyDescriptor
(columnName.toLowerCase(), beanClass);
Method writeMethod = pd.getWriteMethod();
writeMethod.invoke(bean, value);
}
beanList.add(bean);
}
} catch (Exception e) {
e.printStackTrace();
}
// 14. 返回封装好的对象
return beanList;
}
}
/**
* 查询多条记录
*/
public <T> List<T> queryListForObject(String sql, ResultSetHandler<T> rsh, Object...objs){
List<T> list = new ArrayList<>();
try {
con = dataSource.getConnection();
pst = con.prepareStatement(sql);
ParameterMetaData parameterMetaData = pst.getParameterMetaData();
int count = parameterMetaData.getParameterCount();
if( count != objs.length){
throw new RuntimeException("参数个数不匹配");
}
for(int i=0; i< objs.length;i++){
pst.setObject(i+1,objs[i]);
}
rs = pst.executeQuery();
list = rsh.handler(rs);
} catch (Exception e) {
e.printStackTrace();
} finally {
DataSourceUtils.close(con, pst);
}
return list;
}
@Test
public void queryForList(){
String sql = "SELECT * FROM student";
List<Student> list = template.queryListForObject(sql, new BeanListHandler<>(Student.class));
for(Student stu : list){
System.out.println(stu);
}
}
查询聚合函数
package com.test005.handler;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
/**
* 1. 定义一个类, 实现ResultSetHandler接口
* 2. 我一定handler方法
* 3. 定义一个Long类型变量
* 4. 判断结果集对象中是否还有数据
* 5. 获取结果集源信息的对象
* 6. 获取第一列的列名
* 7. 根据列名获取该列的值
* 8. 返回结果
*/
// * 1. 定义一个类, 实现ResultSetHandler接口
public class ScalarHandler <T> implements ResultSetHandler<T>{
//2. 我一定handler方法
@Override
public Long handler(ResultSet rs) {
// 3. 定义一个Long类型变量
Long value = null;
try {
// 4. 判断结果集对象中是否还有数据
if(rs.next()){
// 5. 获取结果集源信息的对象
ResultSetMetaData metaData = rs.getMetaData();
//6. 获取第一列的列名
String columnName = metaData.getColumnName(1);
// 7. 根据列名获取该列的值
value = rs.getLong(columnName);
}
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
}
/**
* 聚合聚合函数的查询结果
*/
public Long queryForScalar(String sql, ResultSetHandler<Long> rsh, Object...objs){
Long value = null;
try {
con = dataSource.getConnection();
pst = con.prepareStatement(sql);
ParameterMetaData parameterMetaData = pst.getParameterMetaData();
int count = parameterMetaData.getParameterCount();
if( count != objs.length){
throw new RuntimeException("参数个数不匹配");
}
for(int i=0; i< objs.length;i++){
pst.setObject(i+1,objs[i]);
}
rs = pst.executeQuery();
value = rsh.handler(rs);
} catch (Exception e) {
e.printStackTrace();
} finally {
DataSourceUtils.close(con, pst);
}
return value;
}
@Test
public void queryForScalar(){
String sql = "SELECT COUNT(*) FROM student";
Long value = template.queryForScalar(sql, new ScalarHandler<Long>());
System.out.println(value);
}