Dao设计模式(Data Access Object)
目 录(本篇字数:1858)
-
介绍
Dao设计模式(Data Access Object),称为数据访问对象。它是对于数据库操作的一种设计方式,把Dao设计为一个通用接口,提供对数据库进行增、删、改、查的一系列操作数据库的抽象方法。
面向对象编程的核心就是类、对象。数据库中每一张Table可以看作一个Class,而列就可以看作类中的一些属性。这是面向对象的基本思想,通过这种思想我们需要提供的Class就相当于Table的数量。而每次对数据库的操作时,根据查询的Table不同,就会得到不同的Class。
又因为每个Class中操作增、删、改、查的方法都大相近庭,这就造成的代码的冗余、所以就出现Dao的设计思想。利用Dao接口提供的抽象方法对数据库进行操作就大大的降低代码重复,间接地可以提高程序的效率、性能等。
-
通用Dao
下面我们来编写一个通用的Dao,虽然有许多第三方的开源框架,其内部实现也是万变不离其中。其中用到数据库连接池(c3p0、dbcp)与DBUtils工具包,如果对这几个包的使用不是很清楚的话,推荐我写的上篇文章:数据库连接池(dbcp、c3p0)与DBUtils工具包的使用
一、Dao泛型接口
下面是我们的Dao接口代码,提供了几种最基本的增、删、改、查的抽象方法。该接口传入一个泛型的实体类(如:UserBean)。
public interface Dao<T> {
// 提供查询一个 bean
T query(Connection conn, String sql, Object... args) throws SQLException;
// 提供查询一个列表,如 beanList
List<T> queryAll(Connection conn, String sql, Object... args) throws SQLException;
// 提供查询单个值
Object queryValue(Connection conn, String sql, Object... args) throws SQLException;
// 提供增、删、改的操作
void update(Connection conn, String sql, Object... args) throws SQLException;
}
二、JavaBean
UserBean类,该类作为数据库映射到类的基础。
package com.xww;
public class User {
public String userName;
public String password;
public String registerTime;
public String sex;
public String userRole;
public String idCard;
public User() {
super();
}
public User(String userName, String password, String registerTime,
String sex, String userRole, String idCard) {
super();
this.userName = userName;
this.sex = sex;
this.userRole = userRole;
this.password = password;
this.idCard = idCard;
this.registerTime = registerTime;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getUserRole() {
return userRole;
}
public void setUserRole(String userRole) {
this.userRole = userRole;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
public String getRegisterTime() {
return registerTime;
}
public void setRegisterTime(String registerTime) {
this.registerTime = registerTime;
}
@Override
public String toString() {
return "User [userName=" + userName + ", password=" + password + ", registerTime=" + registerTime + ", sex="
+ sex + ", userRole=" + userRole + ", idCard=" + idCard + "]\n";
}
}
三、Dao接口实现类
接着,我们有了Dao接口和JavaBean就应该编写Dao接口的实现类。
package com.xww;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
public class DaoImpl<T> implements Dao<T> {
QueryRunner queryRunner = null;
Class<T> type = null;
public DaoImpl() {
queryRunner = new QueryRunner();
System.out.println(this.getClass());
type = ReflectionUtils.getSuperGenericType(getClass());
}
@Override
public T query(Connection conn, String sql, Object... args) throws SQLException {
return queryRunner.query(conn, sql, new BeanHandler<T>(type), args);
}
@Override
public List<T> queryAll(Connection conn, String sql, Object... args) throws SQLException {
return queryRunner.query(conn, sql, new BeanListHandler<T>(type), args);
}
@Override
public Object queryValue(Connection conn, String sql, Object... args) throws SQLException {
return queryRunner.query(conn, sql, new ScalarHandler<T>(), args);
}
@Override
public void update(Connection conn, String sql, Object... args) throws SQLException {
queryRunner.update(conn, sql, args);
}
}
该类有一个Class<T> type 类型的变量,那么这个type类型就是我们传入的JavaBean(本例子中就是:User类)。这里涉及到利用Java反射来获取运行时中类的父类中传入的泛型 T 。如果对反射不懂的可以看这篇文章:Java反射机制(Reflection)获取运行时类的结构
还有一个类是UserDao,它继承了DaoImpl类,拥有了父类的方法,同时在需求更改的情况下,可以进行对UserDao的拓展,在本例子中,并没有什么需要拓展的,就可以写为这样,传入一个类型为User的泛型即可。
package com.xww;
public class UserDao extends DaoImpl<User> {
}
四、单元测试
再接着,是我们的单元测试类,提供对Dao接口设计的测试,在实际运用中也是如此使用。
package com.xww;
import static org.junit.Assert.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import org.junit.Test;
public class UserDaoTest {
UserDao userDao = new UserDao();
@Test
public void testQuery() {
Connection conn = null;
String sql = "select username,password,registertime,sex,userrole,idcard from user where username=?";
conn = JdbcUtils.getConnectionForC3P0();
try {
User user = (User) userDao.query(conn, sql, "小王");
System.out.println(user);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(null, conn, null);
}
}
@Test
public void testQueryAll() {
Connection conn = null;
String sql = "select username,password,registertime,sex,userrole,idcard from user";
conn = JdbcUtils.getConnectionForC3P0();
try {
List<User> users = (List<User>) userDao.queryAll(conn, sql);
System.out.println(users);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(null, conn, null);
}
}
@Test
public void testQueryValue() {
Connection conn = null;
String sql = "select userrole from user where username=?";
conn = JdbcUtils.getConnectionForC3P0();
try {
Object val = userDao.queryValue(conn, sql, "小王");
System.out.println(val);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(null, conn, null);
}
}
@Test
public void testUpdate() {
Connection conn = null;
String sql = "update user set userrole=? where username=?";
conn = JdbcUtils.getConnectionForC3P0();
try {
userDao.update(conn, sql, "普通用户", "小王");
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(null, conn, null);
}
}
}
这里要注意一下:我们的UserDao继承自UserImpl,所以我们new的一个对象是UserDao的,即在UserImpl中获取的getClass()对象便是UserDao的对象,这里得区别清楚,否则获取父类的泛型会有一个坑。
五、反射工具类
最后,是我们的获取父类的泛型的一个工具类:
package com.xww;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class ReflectionUtils {
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz, int index) {
Type genType = clazz.getGenericSuperclass();
System.out.println(genType);
if (!(genType instanceof ParameterizedType)) {
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
return Object.class;
}
if (!(params[index] instanceof Class)) {
return Object.class;
}
return (Class) params[index];
}
@SuppressWarnings("unchecked")
public static <T> Class<T> getSuperGenericType(Class clazz) {
return getSuperClassGenricType(clazz, 0);
}
public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes) {
for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
// superClass.getMethod(methodName, parameterTypes);
return superClass.getDeclaredMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
return null;
}
public static void makeAccessible(Field field) {
if (!Modifier.isPublic(field.getModifiers())) {
field.setAccessible(true);
}
}
public static Field getDeclaredField(Object object, String filedName) {
for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
return superClass.getDeclaredField(filedName);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
return null;
}
public static Object invokeMethod(Object object, String methodName, Class<?>[] parameterTypes, Object[] parameters)
throws InvocationTargetException {
Method method = getDeclaredMethod(object, methodName, parameterTypes);
if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
}
method.setAccessible(true);
try {
return method.invoke(object, parameters);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static void setFieldValue(Object object, String fieldName, Object value) {
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
makeAccessible(field);
try {
field.set(object, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static Object getFieldValue(Object object, String fieldName) {
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
makeAccessible(field);
Object result = null;
try {
result = field.get(object);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return result;
}
}
数据库User Table:
©原文链接:https://blog.csdn.net/smile_Running/article/details/86767924
@作者博客:_Xu2WeI
@更多博文:查看作者的更多博文