1、在数据库的查找过程中,有的时候会涉及到返回一个集合,有的时候会涉及到返回一个具体的实体类,应做到可灵活的处理select的返回结果
2、为了方便的处理ResultSet的返回结果,定义了下面的接口和实现类
2.1 ResultSetHandle
package com.jdbc.enhancegenericity.utils;
import java.sql.ResultSet;
/**
* 用于处理select返回的ResultSet,是实体类的集合,还是一个单一的实体类
*
* @param <T>
* 泛型T,在调用的时候传入具体的处理结果;例如User或者List<User>
*/
public interface ResultSetHandle<T> {
/**
*
* @param rs
* select语句执行后,返回的ResultSet结果集
* @return 返回实体,或者集合,看具体的实现类
*/
public T handle(ResultSet rs);
}
2.2 BeanHandle
package com.jdbc.enhancegenericity.utils;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
/**
*
* ResultSetHandle<T>接口的实现类,用于处理select语句返回一个具体实体的情况
*
* @param <T>
*/
public class BeanHandle<T> implements ResultSetHandle<T> {
/**
* 用于保存具体实体类的Class对象
*/
private Class<T> clazz;
/**
* 在构造BeanHandle的时候,传入具体实体的Class对象
*
* @param clazz
* 具体实体的Class对象
*/
public BeanHandle(Class<T> clazz) {
this.clazz = clazz;
}
@Override
public T handle(ResultSet rs) {
try {
// 如果查询的ResultSet结果集为空,直接返回null
if (!rs.next()) {
return null;
}
T bean = clazz.newInstance();
// 得到结果集的元数据
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount();
for (int i = 0; i < count; i++) {
// 注意jdbc的下标,从1开始
// 去获取到数据库中的列的名称
String name = metaData.getColumnName(i + 1);
// 获取到,数据库列对应的数值
Object value = rs.getObject(name);
// 反射bean上与列名相同的属性
Field f = bean.getClass().getDeclaredField(name);
f.setAccessible(true);
f.set(bean, value);
}
// 返回查询到的实体对象
return bean;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
2.3 ListBeanHandle
package com.jdbc.enhancegenericity.utils;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
/**
*
* 因为ListBeanHandle<T>是用于处理返回结果是集合的情况, 所以要注意ResultSetHandle<List<T>>的具体写法
*
* @param <T>
*/
public class ListBeanHandle<T> implements ResultSetHandle<List<T>> {
/**
* 用于保存具体实体类的Class对象
*/
private Class<T> clazz;
/**
* 在构造BeanHandle的时候,传入具体实体的Class对象
*
* @param clazz
* 具体实体的Class对象
*/
public ListBeanHandle(Class<T> clazz) {
this.clazz = clazz;
}
@Override
public List<T> handle(ResultSet rs) {
try {
List<T> lists = new ArrayList<T>();
while (rs.next()) {
T bean = clazz.newInstance();
// 得到结果集的元数据
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount();
for (int i = 0; i < count; i++) {
// 注意jdbc的下标,从1开始
// 去获取到数据库中的列的名称
String name = metaData.getColumnName(i + 1);
// 获取到,数据库列对应的数值
Object value = rs.getObject(name);
// 反射bean上与列名相同的属性
Field f = bean.getClass().getDeclaredField(name);
f.setAccessible(true);
f.set(bean, value);
}
// 将得到的记录加入到lists中
lists.add(bean);
}
// 返回查询到的实体对象的集合lists
return lists;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
package com.jdbc.enhancegenericity.utils;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import com.jdbc.entity.User;
import com.jdbc.utils.MyJDBCUtils;
public class GenericityJDBCUtils {
private static Connection conn;
private static PreparedStatement pstate;
private static ResultSet rs;
// 为了程序的更好的解耦合,利用Properties文件保存连接Mysql的配置文件
private static Properties config = new Properties();
/**
* 使用static块,加载数据库的配置文件和数据库的驱动
*/
static {
try {
config.load(MyJDBCUtils.class.getClassLoader().getResourceAsStream(
"db.properties"));
Class.forName(config.getProperty("driver"));
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
/**
* 获取一个数据库的连接
*
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(config.getProperty("url"),
config.getProperty("username"),
config.getProperty("password"));
} catch (SQLException e) {
throw new RuntimeException("获取连接Mysql数据库连接失败");
}
return conn;
}
/**
* 释放数据库的连接
*
* @param conn
* @param st
* @param rs
*/
public static void release(Connection conn, Statement st, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
throw new RuntimeException("ResultSet关闭异常");
}
rs = null;
}
if (st != null) {
try {
st.close();
} catch (Exception e) {
throw new RuntimeException("Statement关闭异常");
}
st = null;
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
throw new RuntimeException("Connection关闭异常");
}
conn = null;
}
}
/**
*
* @param clazz
* 要返回的类型的字节码
* @param id
* 要查找记录在表里面的id
* @return 在数据库里面查找到的记录,并返回
*/
public static <T> T findById(Class<T> clazz, int id) {
T bean = null;
// System.out.println(clazz.getSimpleName());
try {
bean = clazz.newInstance();
String tableName = clazz.getSimpleName();
String sql = "select * from " + tableName + " where id = ? ";
conn = getConnection();
pstate = conn.prepareStatement(sql);
pstate.setInt(1, id);
rs = pstate.executeQuery();
if (rs.next()) {
// 得到结果集的元数组
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount();
for (int i = 0; i < count; i++) {
// 注意jdbc的下标,从1开始
// 去获取到数据库中的列的名称
String name = metaData.getColumnName(i + 1);
// 获取到,数据库列对应的数值
Object value = rs.getObject(name);
// 反射bean上与列名相同的属性
Field f = bean.getClass().getDeclaredField(name);
f.setAccessible(true);
f.set(bean, value);
}
}
return bean;
} catch (Exception e) {
throw new RuntimeException("在数据库中,查找id为" + id + "的User记录失败." + e);
} finally {
// 释放资源,关闭与数据库的连接
release(conn, pstate, rs);
}
}
/**
* 郑强版本的sql查询,支持查询一个具体的实体或者是一个实体集合
*
* @param sql
* 查询的sql语句
* @param args
* 对应sql语句中的参数
* @param handle
* 具体的ResultSet处理器, BeanHandle用于处理一个具体的实体类,
* ListBeanHandle用于处理返回一个集合的情况
* @return
*/
public static <T> T query(String sql, Object[] args,
ResultSetHandle<T> handle) {
try {
// 获取连接Connection
conn = getConnection();
// 获取PreparedStatement
pstate = conn.prepareStatement(sql);
// 设置参数
for (int i = 0; i < args.length; i++) {
pstate.setObject(i + 1, args[i]);
}
// 获取rs
rs = pstate.executeQuery();
// 通过ResultSetHandle处理ResultSet,并返回结果
return handle.handle(rs);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
release(conn, pstate, rs);
}
}
/**
* 适应于sql语句不带参数的问题
*
* @param sql
* @param handle
* @return
*/
public static <T> T query(String sql, ResultSetHandle<T> handle) {
try {
// 获取连接Connection
conn = getConnection();
// 获取PreparedStatement
pstate = conn.prepareStatement(sql);
// 获取rs
rs = pstate.executeQuery();
// 通过ResultSetHandle处理ResultSet,并返回结果
return handle.handle(rs);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
release(conn, pstate, rs);
}
}
/**
* 根据传进来的sql语句,来跟新数据库的表记录
*
* @param sql
* @param args
*/
public static void update(String sql, Object[] args) {
try {
if (args.length < 0) {
throw new RuntimeException("Object[] args的数组长度,不应该为空");
}
conn = getConnection();
pstate = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
pstate.setObject(i + 1, args[i]);
}
// 注意要调用这个方法
pstate.executeUpdate();
} catch (Exception e) {
throw new RuntimeException("更新数据库中的记录失败" + e);
} finally {
// 释放资源,关闭与数据库的连接
release(conn, pstate, null);
}
}
/**
* 根据sql语句来更新数据库表中的记录
*
* @param sql
*/
public static void update(String sql) {
try {
conn = getConnection();
pstate = conn.prepareStatement(sql);
// 注意要调用这个方法
pstate.executeUpdate();
} catch (Exception e) {
throw new RuntimeException("更新数据库中的记录失败" + e);
} finally {
// 释放资源,关闭与数据库的连接
release(conn, pstate, null);
}
}
}
4、测试代码
package com.jdbc.enhancegenericity.utils;
import java.util.List;
import org.junit.Test;
import com.jdbc.entity.Person;
import com.jdbc.entity.User;
public class GenericityJDBCUtilsTest {
@Test
public void testQuery() {
String sql = "select * from user ";
List<User> users = GenericityJDBCUtils.query(sql,
new ListBeanHandle<User>(User.class) {
});
for (int i = 0; i < users.size(); i++) {
System.out.println(users.get(i));
}
sql = "select * from person where id = ? ";
Person person = GenericityJDBCUtils.query(sql, new Object[] { 1 },
new BeanHandle<Person>(Person.class));
System.out.println(person);
}
}
5、数据库数据
6、程序运行结果