之前写过一个JDBC通用的DAO工具类,感觉不完美的地方是用到了第三方的BeanUtils的jar包,那就没什么意思了。现在改进一下,模拟一个Spring的JdbcTemplate工具类。使用的时候,传入一个数据源就可以了。
?
import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;/*** JDBC工具类*/
public class JdbcTemplate {private DataSource dataSource;//通过构造方法传入数据源对象public JdbcTemplate(DataSource dataSource) {this.dataSource = dataSource;}/*** 获取连接对象的方法*/public Connection getConnection() throws SQLException {return dataSource.getConnection();}/*** 增删改的通用方法* @param sql SQL语句* @param param 替换占位符的真实值,可变参数在方法中是一个数组,数组索引从0开始* @return 影响的行数*/public int update(String sql, Object... param) {Connection connection = null;PreparedStatement ps = null;//影响的行数int row = 0;try {//1.获取连接对象connection = getConnection();//2.创建预编译的语句对象,提供SQL语句,并且有占位符ps = connection.prepareStatement(sql);//3.替换占位符为真实的数据//3.1 获取参数元数据对象ParameterMetaData parameterMetaData = ps.getParameterMetaData();//3.2 通过参数元数据获取占位符的个数int count = parameterMetaData.getParameterCount();//3.3 给每个占位符赋值for (int i = 0; i < count; i++) {ps.setObject(i + 1, param[i]);}//4.执行增删改操作row = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();} finally {//5.释放资源close(connection, ps);}return row;}/*** 通用的查询方法* @param sql SQL语句* @param clazz 要封装的每个元素的类型,如:Student.class Account.class* @param param 替换占位符的真实值**/public <T> List<T> query(String sql, Class<T> clazz, Object...param) {//0.创建一个集合对象List<T> list = new ArrayList<>();Connection connection = null;PreparedStatement ps = null;ResultSet resultSet = null;try {//1.创建连接对象connection = getConnection();//2.创建预编译的语句对象,提供SQL语句ps = connection.prepareStatement(sql);//3.替换占位符//3.1 获取参数元数据对象ParameterMetaData parameterMetaData = ps.getParameterMetaData();//3.2 通过参数元数据获取占位符的个数int count = parameterMetaData.getParameterCount();//3.3 给每个占位符赋值for (int i = 0; i < count; i++) {ps.setObject(i + 1, param[i]);}//4.执行SQL语句resultSet = ps.executeQuery();//获取结果集元数据ResultSetMetaData metaData = resultSet.getMetaData();//获取总列数int columnCount = metaData.getColumnCount();//5.得到结果集,遍历结果集,封装成List对象while (resultSet.next()) {//每次遍历创建一个对象进行封装,获取无参的构造方法,再进行实例化T obj = clazz.getConstructor().newInstance();//循环给每个属性赋值for (int i = 1; i <= columnCount; i++) {//获取这一列的名字,与类中成员变量名字是一样的String columnName = metaData.getColumnName(i);//从结果集中取出这一列的值Object value = resultSet.getObject(columnName);//通过名字获取相应的属性对象Field field = clazz.getDeclaredField(columnName);//设置为暴力反射field.setAccessible(true);//给属性赋值,参数1:要赋值的对象,参数2:要赋的值field.set(obj, value);}//添加到集合中list.add(obj);}} catch (Exception e) {e.printStackTrace();} finally {//6.释放资源close(connection, ps, resultSet);}//返回集合对象return list;}/*** 编写释放资源的方法* @param connection 连接对象* @param statement 语句对象* @param resultSet 结果集*/public void close(Connection connection, Statement statement, ResultSet resultSet) {try {if (resultSet != null) {resultSet.close();}} catch (SQLException e) {e.printStackTrace();}try {if (statement != null) {statement.close();}} catch (SQLException e) {e.printStackTrace();}try {if (connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}/*** 编写释放资源的方法* @param connection 连接对象* @param statement 语句对象*/public void close(Connection connection, Statement statement) {close(connection, statement, null);}
}