JDBC-DAO
JDBC-DAO
DAO:Data Access Object,数据访问对象
DAO就是将JAVA对表的操作封装成对象
一张表对应一个实体类,那么一张表的操作对应一个DAO对象
在Java操作数据库时,我们将对同一张表的操作封装起来,供业务层Service去调用,这个类就是DAO层
在dao目录下建立xxxDao接口
在dao目录下建立impl目录建立实现类
在dao目录下建立BaseDAO父类
BaseDAO
基本上每一个数据表都应该有一个对应的DAO接口及其实现类
我们发现所有表的CURD代码重复率很高,所以我们可以将这些重复的代码设计一个公共的父类
注:BaseDAO中是不写SQL代码的,而DAO的实现类是需要写具体的SQL功能的
DAO处理一共分为六步
- 注册驱动
- 获取链接
- 预编译SQL语句
- 为占位符赋值,执行SQL,接受返回结果
- 处理结果
- 释放资源
其中,1、2、6三部我们通过JDBCUtil完成,需要编写BaseDao提取出3、4、5的代码冗余部分
在这里,我们设计三个方法去完成公共部分的增删改查功能:
import com.xiaobai.schedule.util.JDBCUtilV2;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 此类是封装JDBC中 预编译Sql -> 为占位符赋值 -> 处理结果三个步骤的代码
* 此类直接作为Dao实现类的父类,不重写代码直接继承封装好的方法
*/
public class BaseDAO {
/**
* 通用的增删改操作,形参使用可变长参数
*
* @param sql 传入增删改的sql语句
* @param params 传入对应sql语句的参数
* @return 返回数据库受操作改变的行数
* @throws SQLException
*/
public int executeUpdate(String sql, Object... params) throws SQLException {
//获取连接(通过封装好的工具类JDBCUtilV2)
Connection connection = JDBCUtilV2.getConnection();
//预编译SQL语句,来源于形参
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//为SQL语句的占位符提供参数
if (params != null && params.length > 0) {
for (int i = 0; i < params.length; i++) {
//占位符从1开始,数组下表从0开始
preparedStatement.setObject(i + 1, params[i]);//这里可以用setObject通配所有参数类型
}
}
int i = preparedStatement.executeUpdate();
//释放资源
preparedStatement.close();
JDBCUtilV2.close();
//将返回来的行数,直接作为方法的返回值
return i;
}
/**
* 查询的返回的结果的类型不唯一,使用泛型方法
* 结果的封装使用反射:告诉调用者告知BaseDao要封装对象的类对象
*
* @param clazz 传入实体类的class类(通过.class即可获取)
* @param sql 传入查询的sql语句
* @param params 传入对应sql语句的参数
* @param <T> 结果集合(List)中参数的类型
* @return 返回一个结果集合,这个结果集合是被查询的结果(单行单列、单行多列、多行多列)
* @throws Exception
*/
public <T> List<T> executeQuery(Class<T> clazz, String sql, Object... params) throws Exception {
//获取连接(通过封装好的工具类JDBCUtilV2)
Connection connection = JDBCUtilV2.getConnection();
//预编译SQL语句,来源于形参
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//为SQL语句的占位符提供参数
if (params != null && params.length > 0) {
for (int i = 0; i < params.length; i++) {
//占位符从1开始,数组下表从0开始
preparedStatement.setObject(i + 1, params[i]);//这里可以用setObject通配所有参数类型
}
}
//执行SQL,处理结果
ResultSet resultSet = preparedStatement.executeQuery();
//处理结果的元数据对象(包含列的名称和数量)
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();//列的数量
List<T> list = new ArrayList<T>();//建立一个集合存放遍历并返回
//循环行
while (resultSet.next()) {
T t = clazz.newInstance();//每行都是一个T类型的对象t
//遍历列(注意,结果集的属性从1开始)
for (int i = 1; i <= columnCount; i++) {
Object value = resultSet.getObject(i);//通过下标获取值
String fieldName = metaData.getColumnLabel(i);//通过下标获取列的名称
//以下代码使用反射,获取到T类的私有属性
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(t, value);
}
list.add(t);//每获取一行变量的对象,就放在集合中
}
//释放资源
resultSet.close();
preparedStatement.close();
JDBCUtilV2.close();
return list;
}
/**
* 通用查询单行单列,单行多列的结果集处理。
* 通过调用executeQuery方法获得List,对List进行处理
*
* @param clazz 传入实体类的class类(通过.class即可获取)
* @param sql 传入查询的sql语句
* @param params 传入对应sql语句的参数
* @param <T> 结果集合(List)中参数的类型
* @return 返回一个结果(单行单列、单行多列),这个结果不再是集合,而是一个实体类对象
* @throws Exception
*/
public <T> T executeQueryBean(Class<T> clazz, String sql, Object... params) throws Exception {
List<T> list = executeQuery(clazz, sql, params);
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
}
}
DAO实现类
在编写BaseDAO 查询的时候,我们注意到一个事情
当利用反射获取到该类的属性时,我们传入的参数时结果集中列的名字
但是Java中使用的是驼峰命名法,也就是说:类中属性名≠结果集列名
我们可以通过给结果集列名起别名的方法解决这个问题
package com.xiaobai.dao.impl;
import com.xiaobai.dao.BaseDAO;
import com.xiaobai.dao.UserDao;
import com.xiaobai.pojo.User;
import java.sql.SQLException;
import java.util.List;
public class UserDaoImpl extends BaseDAO implements UserDao {
//查询所有
@Override
public List<User> selectAll() {
try {
String sql = "select u_id userId,u_name userName,u_salary userSalary,u_age userAge from user";//起别名解决反射问题
return executeQuery(User.class, sql, null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//根据id查询一条数据
@Override
public User selectByUserId(int id) {
try {
String sql = "select u_id userId,u_name userName,u_salary userSalary,u_age userAge from user where u_id = ?";
return executeQueryBean(User.class, sql, id);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//插入一条数据
@Override
public int insert(User user) {
try {
String sql = "INSERT INTO user(u_name, u_salary, u_age) VALUES (?, ?, ?)";
return executeUpdate(sql, user.getUserName(), user.getUserSalary(), user.getUserAge());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//修改员工的薪资
@Override
public int update(User user) {
try {
String sql = "UPDATE user SET u_salary = ? WHERE u_id = ?";
return executeUpdate(sql, user.getUserSalary(), user.getUserId());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//根据id删除一条数据
@Override
public int delete(int id) {
try {
String sql = "DELETE FROM user WHERE u_id = ?";
return executeUpdate(sql, id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}