DAO模式设计
标签: jdbc
什么是DAO
Data Access Object,数据库访问对象,主要的功能就是用于进行数据操作的CRUD(create,read,update,delete),而不包含任何业务相关的信息。在程序的标准开发架构中属于数据层的操作。
实现了功能的模块化。更有利于代码的维护和升级。
如何编写DAO
DAO可以被继承或直接使用。使用JDBC编写DAO可能会包含的方法:
INSERT,UPDATE,DELDETE操作都可以包含在其中
void update(String sql,Object ... args);
查询一条记录,返回对应的对象
<T> T get(Class<T> clazz,String sql,Object ... args);
- 查询多条记录,返回对应的对象的集合
<T> List<T> getForList(Class<T> clazz,String sql,Object ... args);
- 返回某条记录的某一个字段的值,或一个统计的值(一共有多少条记录等)
<E> E getForValue(String sql,Object ... args);
BeanUtils获取Java类的属性
在JavaEE中,Java类的属性通过getter,setter来定义:get(或set)方法,取出get(或set)后首字母小写后即为Java类的属性
以前所说的属性,也就是成员变量,称之为字段。
操作Java类的属性有一个工具包:beanutils
我们需要在项目中导入beanutils以及logging的jar包
我们通过beanutils工具包的方法来操作属性:
给对象object的属性赋值:
BeanUtils.setProperty(Object bean,String name,Object value);
获取对象object的属性:
Object val = BeanUtils.getProperty(Object bean,String name);
DAO中的方法
增删改操作:update
/**
* INSERT,UPDATE,DELDETE操作都可以包含在其中
* @param sql 传入的sql语句
* @param args 占位符的可变参数
*/
public void update(String sql, Object... args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JDBCTools.getConnection();
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.release(null, preparedStatement, connection);
}
}
查询单条记录操作:get
/**
* 查询一条记录,返回对应的对象
* @param clazz 要查询的对象的类
* @param sql 传入的sql语句
* @param args 占位符的可变参数
* @param <T> 泛型
* @return
*/
public <T> T get(Class<T> clazz, String sql, Object... args) {
T entity = null;
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//1. 获取Connection连接
connection = JDBCTools.getConnection();
//2. 获取PreparedStatement对象
preparedStatement = connection.prepareStatement(sql);
//3. 填充占位符
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
//4. 进行查询,达到结果集
resultSet = preparedStatement.executeQuery();
//5. 创建一个Map
Map<String, Object> map = new HashMap<>();
//6. 得到ResultSetMetaData对象
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
//7. 处理结果集,指针向下移
//while循环没进来,把前面的if(resultSet.next())去掉就好了
while (resultSet.next()) {
//8. 得到ResultSetMetaData的列数
int columnCount = resultSetMetaData.getColumnCount();
//9. 由ResultSetMetaData得到每一个列的别名,由ResultSet得到具体每一列的值
for (int i = 0; i < columnCount; i++) {
String columnLabel = resultSetMetaData.getColumnLabel(i + 1);
Object columnValue = resultSet.getObject(i + 1);
//10.填充Map
map.put(columnLabel, columnValue);
}
//11. 利用反射创建Class实体对象
entity = clazz.newInstance();
//12. 遍历Map对象,用反射填充对象的属性值
for (Map.Entry<String, Object> entry : map.entrySet()) {
String propertyName = entry.getKey();
Object value = entry.getValue();
//ReflectionUtils.setFieldValue(entity, propertyName, value);
BeanUtils.setProperty(entity, propertyName, value);
}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.release(resultSet, preparedStatement, connection);
}
return entity;
}
查询多条记录操作getForList
/**
* 查询多条记录,返回对应的对象的集合
* @param clazz 要查询的对象的类
* @param sql 传入的sql语句
* @param args 占位符的可变参数
* @param <T> 泛型
* @return
*/
public <T> List<T> getForList(Class<T> clazz, String sql, Object... args) {
List<T> list = new ArrayList<>();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//1. 建立Connection连接
connection = JDBCTools.getConnection();
//2. 创建PreparedStatement对象
preparedStatement = connection.prepareStatement(sql);
//3. 填充占位符
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
//4. 查询得到结果集
resultSet = preparedStatement.executeQuery();
//5. 准备多个Map:List<Map<String,Object>>,每一个Map对应一条查询记录
List<Map<String, Object>> values = new ArrayList<>();
//6. 得到ResultSetMetaData对象
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
Map<String, Object> map = null;
//7. 处理ResultSet,使用while循环
while (resultSet.next()) {
//集合中的每一个map
map = new HashMap<>();
//8. 得到ResultSetMetaData的列数
int columnCount = resultSetMetaData.getColumnCount();
//9. 由ResultSetMetaData得到字段的别名,由ResultSet得到字段的值
for (int i = 0; i < columnCount; i++) {
String columnLabel = resultSetMetaData.getColumnLabel(i + 1);
Object value = resultSet.getObject(i + 1);
//10. 填充Map对象
map.put(columnLabel, value);
}
//11. 把填充好的Map对象放入List中
values.add(map);
}
//12. 判断List是否为空集合,若不为空,则遍历List,得到一个一个的Map对象
//再把Map对象转为一个Class参数对应的Object对象
T bean = null;
if (values.size() > 0) {
//遍历列表中的map
for (Map<String, Object> m : values) {
//每找到一个map,就要利用反射创建一个实例对象
bean = clazz.newInstance();
//通过遍历map中的键值对,给实例对象赋值
for (Map.Entry<String, Object> entry : m.entrySet()) {
String propertyName = entry.getKey();
Object value = entry.getValue();
//通过beanUtils给对象的属性赋值
BeanUtils.setProperty(bean, propertyName, value);
}
//13.把Object对象放入到List中
list.add(bean);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.release(resultSet, preparedStatement, connection);
}
return list;
}
重构getForList
将很多方法抽取出来,重构
/**
* 查询多条记录,返回对应的对象的集合
* @param clazz 要查询的对象的类
* @param sql 传入的sql语句
* @param args 占位符的可变参数
* @param <T> 泛型
* @return
*/
public <T> List<T> getForList(Class<T> clazz, String sql, Object... args) {
List<T> list = new ArrayList<>();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//1. 得到结果集
connection = JDBCTools.getConnection();
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
resultSet = preparedStatement.executeQuery();
//2. 处理结果集,得到Map的一个List,其中一个Map对象对应一条记录
//其中Map的key为resultSet中列的别名,Map的value为列的值。
List<Map<String, Object>> values = handleResultSetToMapList(resultSet);
//3. 把Map的List转为clazz对应的list
// 其中Map的key为clazz对应的对象的propertyName,Map的值为clazz对应的对象的propertyValue
list = transfterMapListToBeanList(clazz, values);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.release(resultSet, preparedStatement, connection);
}
return list;
}
/**
* 将Map列表中的键值对赋给list对象中
* @param clazz
* @param values
* @param <T>
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private <T> List<T> transfterMapListToBeanList(Class<T> clazz, List<Map<String, Object>> values) throws InstantiationException, IllegalAccessException, InvocationTargetException {
List<T> result = new ArrayList<>();
T bean = null;
System.out.println(values.size());
if (values.size() > 0) {
//遍历列表中的map
for (Map<String, Object> m : values) {
//把它从内层的for循环拿出来
bean = clazz.newInstance();
//遍历map中的键值对
for (Map.Entry<String, Object> entry : m.entrySet()) {
String propertyName = entry.getKey();
Object value = entry.getValue();
BeanUtils.setProperty(bean, propertyName, value);
}
//13.把Object对象放入到List中
result.add(bean);
}
}
return result;
}
/**
* 处理结果集,得到Map的一个List,其中一个Map对象对应一条记录
* @param resultSet 结果集
* @return list
* @throws SQLException
*/
private List<Map<String, Object>> handleResultSetToMapList(ResultSet resultSet) throws SQLException {
//5. 准备多个Map:List<Map<String,Object>>,每一个Map对应一条查询记录
List<Map<String, Object>> values = new ArrayList<>();
//6. 得到ResultSetMetaData对象
//ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
//调用方法
List<String> columnLabels = getColumnLabels(resultSet);
Map<String, Object> map = null;
//7. 处理ResultSet,使用while循环
while (resultSet.next()) {
map = new HashMap<>();
//8. 得到ResultSetMetaData的列数
//int columnCount = resultSetMetaData.getColumnCount();
//9. 由ResultSetMetaData得到字段的别名,由ResultSet得到字段的值
for (String columnLabel : columnLabels) {
//String columnLabel = resultSetMetaData.getColumnLabel(i + 1);
Object value = resultSet.getObject(columnLabel);
//10. 填充Map对象
map.put(columnLabel, value);
}
//11. 把填充好的Map对象放入List中
values.add(map);
}
return values;
}
/**
* 获取结果集的ColumnLabel对应的集合List
* @param resultSet
* @return
* @throws SQLException
*/
private List<String> getColumnLabels(ResultSet resultSet) throws SQLException {
List<String> labels = new ArrayList<>();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
for (int i = 0;i < resultSetMetaData.getColumnCount();i++) {
labels.add(resultSetMetaData.getColumnLabel(i+1));
}
return labels;
}
重构get方法
利用getForList方法重构get方法
/**
* 查询一条记录,返回对应的对象
* @param clazz 要查询的对象的类
* @param sql 传入的sql语句
* @param args 占位符的可变参数
* @param <T> 泛型
* @return
*/
public <T> T get(Class<T> clazz, String sql, Object... args) {
List<T> result = getForList(clazz,sql,args);
if (result.size() > 0) {
return result.get(0);
}
return null;
}