#### 10.1 DAO概念> DAO:Data Access Object,数据访问对象。 > > Java是面向对象语言,数据在Java中通常以对象的形式存在。一张表对应一个实体类,一张表的操作对应一个DAO对象!
>
> 在Java操作数据库时,我们会将对同一张表的增删改查操作统一维护起来,维护的这个类就是DAO层。 >
在开发中,我们会为数据库中的每一张表创建一个对应的DAO 类,这个 DAO 类专门负责处理与该表相关的所有数据库操作。
- 如果数据库中有一张
user
表(存储用户信息),我们就会创建一个UserDAO
类 - 这个
UserDAO
类中只会包含对user
表的操作方法:- 添加用户(对应
user
表的 INSERT 操作) - 查询用户(对应
user
表的 SELECT 操作) - 更新用户(对应
user
表的 UPDATE 操作) - 删除用户(对应
user
表的 DELETE 操作)
- 添加用户(对应
DAO层只关注对数据库的操作,供业务层Service调用,将职责划分清楚!# 10.1 BaseDAO概念> 基本上每一个数据表都应该有一个对应的DAO接口及其实现类,发现对所有表的操作(增、删、改、查)代码重复度很高,所以可以抽取公共代码,给这些DAO的实现类可以抽取一个公共的父类,复用增删改查的基本操作,我们称为BaseDAO。/*** 通用的查询:多行多列、单行多列、单行单列* 多行多列:List<Employee>* 单行多列:Employee* 单行单列:封装的是一个结果。Double、Integer、。。。。。* 封装过程:* 1、返回的类型:泛型:类型不确定,调用者知道,调用时,将此次查询的结果类型告知BaseDAO就可以了。* 2、返回的结果:通用,List 可以存储多个结果,也可以存储一个结果 get(0)* 3、结果的封装:反射,要求调用者告知BaseDAO要封装对象的类对象。 Class*/
if(params!=null && params.length > 0){
for (int i = 0; i < params.length; i++) {
//占位符是从1开始的。参数的数组是从0开始的
preparedStatement.setObject(i+1,params[i] );
}
}
/*
通用的查询多个Javabean对象的方法,例如:多个员工对象,多个部门对象等
这里的clazz接收的是T类型的Class对象,
如果查询员工信息,clazz代表Employee.class,
如果查询部门信息,clazz代表Department.class,
返回List<T> list
*/
/*
获取结果集的元数据对象。
元数据对象中有该结果集一共有几列、列名称是什么等信息
*/
ResultSetMetaData metaData = res.getMetaData();
int columnCount = metaData.getColumnCount();//获取结果集列数
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;/*** 将共性的数据库的操作代码封装在BaseDAO里。*/
public class BaseDAO {/*** 通用的增删改的方法。* @param sql 调用者要执行的SQL语句* @param params SQL语句中的占位符要赋值的参数* @return 受影响的行数*/public int executeUpdate(String sql,Object... params)throws Exception{//1.通过JDBCUtilV2获取数据库连接Connection connection = JDBCUtilV2.getConnection();//2.预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement(sql);//4.为占位符赋值,执行SQL,接受返回结果if(params!=null && params.length > 0){for (int i = 0; i < params.length; i++) {//占位符是从1开始的。参数的数组是从0开始的preparedStatement.setObject(i+1,params[i] );}}int row = preparedStatement.executeUpdate();//5.释放资源preparedStatement.close();if(connection.getAutoCommit()){JDBCUtilV2.release();}//6.返回结果return row;}/*** 通用的查询:多行多列、单行多列、单行单列* 多行多列:List<Employee>* 单行多列:Employee* 单行单列:封装的是一个结果。Double、Integer、。。。。。* 封装过程:* 1、返回的类型:泛型:类型不确定,调用者知道,调用时,将此次查询的结果类型告知BaseDAO就可以了。* 2、返回的结果:通用,List 可以存储多个结果,也可以存储一个结果 get(0)* 3、结果的封装:反射,要求调用者告知BaseDAO要封装对象的类对象。 Class*/public <T> List<T> executeQuery(Class<T> clazz,String sql,Object... params)throws Exception{//获取连接Connection connection = JDBCUtilV2.getConnection();//预编译SQL语句PreparedStatement preparedStatement = connection.prepareStatement(sql);//设置占位符的值if(params!=null && params.length > 0){for (int i = 0; i < params.length; i++) {preparedStatement.setObject(i+1, params[i]);}}//执行SQL,并接受返回的结果集ResultSet resultSet = preparedStatement.executeQuery();//获取结果集中的元数据对象//包含了:列的数量、每个列的名称ResultSetMetaData metaData = resultSet.getMetaData();int columnCount = metaData.getColumnCount();List<T> list = new ArrayList<>();//处理结果while(resultSet.next()){//循环一次,代表有一行数据,通过反射创建一个对象T t = clazz.newInstance();//循环遍历当前行的列,循环几次,看有多少列for (int i = 1; i <=columnCount ;i++){//通过下表获取列的值Object value = resultSet.getObject(i);//获取到的列的value值,这个值就是t这个对象中的某一个属性//获取当前拿到的列的名字 = 对象的属性名String fieldName = metaData.getColumnLabel(i);//通过类对象和fieldName获取要封装的对象的属性Field field = clazz.getDeclaredField(fieldName);//突破封装的privatefield.setAccessible(true);field.set(t,value);}list.add(t);}resultSet.close();preparedStatement.close();if(connection.getAutoCommit()){JDBCUtilV2.release();}return list;}/*** 通用查询:在上面查询的集合结果中获取第一个结果。 简化了获取单行单列的获取、单行多列的获取*/public <T> T executeQueryBean(Class<T> clazz,String sql,Object... params)throws Exception{List<T> list = this.executeQuery(clazz, sql, params);if(list ==null || list.size() == 0){return null;}return list.get(0);}
}