jdbc DAO封装及BaseDAO工具类
DAO概念
DAO:Data Access Object,数据访问对象。
Java是面向对象语言,数据在Java中通常以对象的形式存在。一张表对应一个实体类,一张表的操作对应一个DAO对象!
在Java操作数据库时,我们会将对同一张表的增删改查操作统一维护起来,维护的这个类就是DAO层。
DAO层只关注对数据库的操作,供业务层Service调用,将职责划分清楚!
还是有user为例
面向接口开发,这边先提供dao接口
package com.qayrup.dao;import com.qayrup.pojo.User;/*** @author qayrup* @version 1.0* @date-time 2025/9/12-10:20* @belongs-project qayrup-study* @belongs-package com.qayrup.dao* @description*/public interface UserDao {User queryUserByNameAndPassword(String name, String password);int insertUser(User user);
}
实现这个接口
package com.qayrup.dao.impl;import com.qayrup.dao.UserDao;
import com.qayrup.pojo.User;
import com.qayrup.utils.JDBCTools;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;/*** @author qayrup* @version 1.0* @date-time 2025/9/12-10:21* @belongs-project qayrup-study* @belongs-package com.qayrup.dao.impl* @description*/public class UserDaoImpl implements UserDao {@Override/*** 根据用户名和密码查询用户信息* @param name 用户名* @param password 密码* @return 查询到的User对象,如果未找到则返回空的User对象* @throws Exception 数据库操作异常*/public User queryUserByNameAndPassword(String name, String password) throws Exception {// 从JDBCTools工具类中获取数据库连接Connection connection = JDBCTools.getConnection();// 定义SQL查询语句,使用占位符防止SQL注入String sql = "select * from user where name = ? and password = ?";// 创建PreparedStatement对象,用于执行预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement(sql);// 设置第一个占位符的值为传入的用户名preparedStatement.setString(1, name);// 设置第二个占位符的值为传入的密码preparedStatement.setString(2, password);// 执行查询操作,获取结果集ResultSet resultSet = preparedStatement.executeQuery();// 创建一个新的User对象用于存储查询结果User user = new User();// 遍历结果集,通常只会有一条记录匹配while (resultSet.next()){// 从结果集中获取id字段值并设置到user对象user.setId(resultSet.getLong("id"));// 从结果集中获取name字段值并设置到user对象user.setName(resultSet.getString("name"));// 从结果集中获取password字段值并设置到user对象user.setPassword(resultSet.getString("password"));// 从结果集中获取type字段值并设置到user对象user.setType(resultSet.getInt("type"));// 从结果集中获取status字段值并设置到user对象user.setStatus(resultSet.getInt("status"));// 从结果集中获取created_at字段值并设置到user对象user.setCreated_at(resultSet.getDate("created_at"));// 从结果集中获取created_by字段值并设置到user对象user.setCreated_by(resultSet.getLong("created_by"));// 从结果集中获取updated_at字段值并设置到user对象user.setUpdated_at(resultSet.getDate("updated_at"));// 从结果集中获取updated_by字段值并设置到user对象user.setUpdated_by(resultSet.getLong("updated_by"));}// 关闭PreparedStatement资源preparedStatement.close();// 返回封装了查询结果的User对象return user;}/*** 插入新的用户信息到数据库* @param user 要插入的User对象* @return 受影响的行数,成功插入返回1* @throws Exception 数据库操作异常*/@Overridepublic int insertUser(User user) throws Exception {// 从JDBCTools工具类中获取数据库连接Connection connection = JDBCTools.getConnection();// 定义SQL插入语句,使用占位符防止SQL注入String sql = "insert into user(name,password,type,status,created_at,created_by,updated_at,updated_by) values(?,?,?,?,?,?,?,?)";// 创建PreparedStatement对象,用于执行预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement(sql);// 设置第一个占位符的值为用户姓名preparedStatement.setString(1, user.getName());// 设置第二个占位符的值为用户密码preparedStatement.setString(2, user.getPassword());// 设置第三个占位符的值为用户类型preparedStatement.setInt(3, user.getType());// 设置第四个占位符的值为用户状态preparedStatement.setInt(4, user.getStatus());// 设置第五个占位符的值为创建时间,将java.util.Date转换为java.sql.DatepreparedStatement.setDate(5, new java.sql.Date(user.getCreated_at().getTime()));// 设置第六个占位符的值为创建者IDpreparedStatement.setLong(6, user.getCreated_by());// 设置第七个占位符的值为更新时间,将java.util.Date转换为java.sql.DatepreparedStatement.setDate(7, new java.sql.Date(user.getUpdated_at().getTime()));// 设置第八个占位符的值为更新者IDpreparedStatement.setLong(8, user.getUpdated_by());// 执行插入操作,返回受影响的行数// 返回插入操作的结果return preparedStatement.executeUpdate();}
}
外部调用
@Testpublic void daoSelect() throws Exception {UserDao userDao = new UserDaoImpl();User user = userDao.queryUserByNameAndPassword("admin", "admin");System.out.println("user = " + user);}
这样有个坏处,那就是每有一张表,就得写一个这种查询,
所以这边将这种基础查询封装
package com.qayrup.dao;import com.qayrup.utils.JDBCTools;import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;/*** @author qayrup* @version 1.0* @date-time 2025/9/12-09:58* @belongs-project qayrup-study* @belongs-package com.qayrup.dao* @description*/public class BaseDao {protected int update(String sql, Object... args) throws Exception {Connection connection = JDBCTools.getConnection();PreparedStatement preparedStatement = connection.prepareStatement(sql);if(args != null && args.length>0){for(int i=0; i<args.length; i++) {preparedStatement.setObject(i+1,args[i]);//?的编号从1开始,不是从0开始,数组的下标是从0开始}}int count = preparedStatement.executeUpdate();preparedStatement.close();if (!connection.getAutoCommit()) return count;//回收JDBCTools.release();return count;}/*通用的查询多个Javabean对象的方法,例如:多个员工对象,多个部门对象等这里的clazz接收的是T类型的Class对象,如果查询员工信息,clazz代表Employee.class,如果查询部门信息,clazz代表Department.class,返回List<T> list*/protected <T> ArrayList<T> query(Class<T> clazz, String sql, Object... args) throws Exception {// 创建PreparedStatement对象,对sql预编译Connection connection = JDBCTools.getConnection();PreparedStatement ps = connection.prepareStatement(sql);//设置?的值if(args != null && args.length>0){for(int i=0; i<args.length; i++) {ps.setObject(i+1, args[i]);//?的编号从1开始,不是从0开始,数组的下标是从0开始}}ArrayList<T> list = new ArrayList<>();ResultSet res = ps.executeQuery();/*获取结果集的元数据对象。元数据对象中有该结果集一共有几列、列名称是什么等信息*/ResultSetMetaData metaData = res.getMetaData();int columnCount = metaData.getColumnCount();//获取结果集列数//遍历结果集ResultSet,把查询结果中的一条一条记录,变成一个一个T 对象,放到list中。while(res.next()){//循环一次代表有一行,代表有一个T对象T t = clazz.newInstance();//要求这个类型必须有公共的无参构造//把这条记录的每一个单元格的值取出来,设置到t对象对应的属性中。for(int i=1; i<=columnCount; i++){//for循环一次,代表取某一行的1个单元格的值Object value = res.getObject(i);//这个值应该是t对象的某个属性值//获取该属性对应的Field对象//String columnName = metaData.getColumnName(i);//获取第i列的字段名//这里再取别名可能没办法对应上String columnName = metaData.getColumnLabel(i);//获取第i列的字段名或字段的别名//通过反射将属性的值设置到t对象中Field field = clazz.getDeclaredField(columnName);//开启暴力反射field.setAccessible(true);//这么做可以操作private的属性//将值设置给t对象field.set(t,value);}list.add(t);}res.close();ps.close();//这里检查下是否开启事务,开启不关闭连接,业务方法关闭!//没有开启事务的话,直接回收关闭即可!if (connection.getAutoCommit()) {//回收JDBCTools.release();}return list;}/*** 通用的查询单个JavaBean对象的方法* @param clazz 指定要查询的JavaBean类型* @param sql 查询SQL语句* @param args SQL中的参数值* @return 返回查询到的第一个对象,如果没有查询到则返回null* @throws Exception 抛出异常*/protected <T> T queryBean(Class<T> clazz,String sql, Object... args) throws Exception {// 调用query方法获取查询结果列表ArrayList<T> list = query(clazz, sql,args);// 如果查询结果为空或者没有数据,则返回nullif(list == null || list.size() == 0){return null;}// 返回查询结果中的第一个对象return list.get(0);}
}
让实现类继承这个封装类
结果