DAO模式和XxxDAO模式

本文详细介绍了DAO模式在Java EE中的应用,包括DAO接口、实现类、DTO、工厂设计及CRUD操作。重点展示了如何通过工厂类动态切换不同数据库实现,以及如何使用BaseDao和继承实现数据访问抽象化。
摘要由CSDN通过智能技术生成

DAO模式

DAO数据访问对象data access object的缩写,用于进行数据操作的封装,在Java程序开发中属于标准开发架构中的持久层的设计模式。

DAO模式是标准JavaEE设计模式之一,用途在于将底层的数据访问操作和高层的业务逻辑分离开。 典型的DAO模式的组成

  • 一个DAO工厂类

  • 一个DAO接口

  • 实现了DAO接口的多种实现类

  • 数据传输对象DTO,有时简称为VO

一个接口,通过接口暴漏当前层中允许调用的方法

	public interface IUserDao {
	public int save(User user);
	public int delete(Long id);
    public int update(User user);//按照id进行修改
	public List<User> query(User user);//user中的非空属性就是查询条件,如果user为null,则查询所有
 }

数据传输对象,在DAO中经常使用实体类来代替

public class User implements Serializable { //建议实体类的名称最好和表名称对应
private Long id; //JavaBean的建议规则:私有属性,共有的get/set方法
private String username;
private String password;
private Date createTime;	//引入驼峰记法

针对DAO访问接口可以有多种实现,最终希望可以在多种实现之间任意切换。例如MySQLUserDaoImpl 是MySQL的实现,OracleUserDaoImpl是针对接口的oracle实现类

public class UserDaoImpl implements IUserDao{
//其它部分自行实现-- 作业
// 按照id值修改用户名或者口令或者用户名和口令,所以sql语句应该是动态的,按照非空属性
进行生成
public int update(User user) {
if (user == null)
throw new IllegalArgumentException("参数不允许为空!");
if (user.getId() == null)
throw new IllegalArgumentException("参数不允许为空!");
int res = 0;
List<Object> params = new ArrayList<>();
StringBuilder sb = new StringBuilder("update tb_users set id=?,");
params.add(user.getId());
if (user.getUsername() != null) {
// 需要判断新用户名是否重复
List<User> userList = this.queryByName(user.getUsername());
if (userList != null && userList.size() > 0) {
User tmp = userList.get(0);
if (tmp.getId() != user.getId() &&
tmp.getUsername().equals(tmp.getUsername()))
throw new IllegalArgumentException("用户名称不允许重复!");
}
sb.append(" username=?,");
params.add(user.getUsername());
}
if (user.getPassword() != null) {
sb.append("password=?,");
params.add(user.getPassword());
    }
if (sb.toString().endsWith(","))
sb.deleteCharAt(sb.length() - 1);
sb.append(" where id=?");
params.add(user.getId());
String sql = sb.toString();
System.out.println(sql);
Connection conn = null;
try {
conn = JdbcUtil.getConnection();
res = JdbcUtil.executeUpdate(conn, sql, params.toArray());
} catch (Exception e) {
throw new IllegalArgumentException(e.getMessage());
} finally {
try {
JdbcUtil.close(null, conn);
} catch (Exception e) {
e.printStackTrace();
}
}
return res;
}
}

最后提供一个工厂类,用于创建具体实现对象,可以通过参数在多种实现之间切换

public class DaoFactory{
public static IUserDao getUserDao(String key){
IUserDao userDao=null;
switch(key){
case "mysql":
userDao=new MySQLUserDaoImpl();
break;
case "oracle":
userDao=new OracleUserDaoImpl();
break;
default:
userDao=new SqlServerUserDaoImpl();
break;
}
return userDao;
}
}

DAO模式

一般的DAO最少需要实现CRUD方法

  • 一个接口、若干实现、一个工厂、一个值bean 接口定义
public interface IBaseDao<T extends Serializable> {
public int save(T t);
public int delete(T t);
public int update(T t); 
public List<T> query(String sql,Object...params); 
}

父类

public abstract class BaseDaoImpl<T extends Serializable> implements
IBaseDao<T> {
private Class<T> clazz;
@SuppressWarnings({ "unchecked", "rawtypes" })
public BaseDaoImpl() {
Class<? extends IBaseDao> clz = this.getClass();
ParameterizedType pt = (ParameterizedType)
clz.getGenericSuperclass();
clazz = (Class) pt.getActualTypeArguments()[0];
}
// insert into tb_users(username,password) values(?,?)
@Override
public int save(T obj) {
StringBuilder sb1 = new StringBuilder("insert into tb_");
sb1.append(clazz.getSimpleName().toLowerCase()).append("(");
StringBuilder sb2 = new StringBuilder(") values(");
Field[] fs = clazz.getDeclaredFields();
List<Object> params = new ArrayList<>();
try {
for (int i = 0; i < fs.length; i++) {
Field f = fs[i];
f.setAccessible(true);
Object val = f.get(obj);
if (val != null) {
sb1.append(f.getName()).append(",");
sb2.append("?,");
params.add(val);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
if (sb1.toString().endsWith(","))
sb1.deleteCharAt(sb1.length() - 1);
if (sb2.toString().endsWith(","))
sb2.deleteCharAt(sb2.length() - 1);
String sql = sb1.toString() + sb2.toString() + ")";
return update(sql, params.toArray());
}
private int update(String sql, Object... params) {
int res = 0;
try {
res = JdbcUtil.executeUpdate(sql, params);
} finally {
JdbcUtil.releaseConnection();
}
return res;
}
// 按照规则:类名称---表名称 列名称---属性
public List<T> findByExample(T obj) {
List<T> res = new ArrayList<>();
try {
StringBuilder sb = new StringBuilder("select * from tb_");
sb.append(clazz.getSimpleName().toLowerCase()).append(" where
1=1 ");
// 生成sql语句
Field[] fs = clazz.getDeclaredFields();
List<Object> params = new ArrayList<>();
for (int i = 0; i < fs.length; i++) {
Field f = fs[i];
f.setAccessible(true);
Object val = f.get(obj);
if (val != null) {
sb.append(" and ").append(f.getName()).append("=? ");
params.add(val);
}
}
ResultSet rs = JdbcUtil.executeQuery(sb.toString(),
params.toArray());
while (rs.next()) {
ResultSetMetaData rsmd = rs.getMetaData();
T t = clazz.newInstance(); // 调用无参构造器构建对象
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
String fieldName = rsmd.getColumnLabel(i); // 获取列名称
Field f = clazz.getDeclaredField(fieldName); // 根据列名称获取对应的Field对象
f.setAccessible(true);
f.set(t, rs.getObject(i)); // 对t对象中对应的属性进行赋值
}
res.add(t);
}
rs.close();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
} finally {
JdbcUtil.releaseConnection();
}
return res;
}
}

获取数据表的元数据

ResultSetMetaData对象保存了所有ResultSet对象中关于字段的信息,提供了对应的方法获取字段相关 的信息

  • int getColumnCount()获取ResultSet对象中的字段个数
  • String getColumnName(int index)获取ResultSet对象中指定序号对应字段的名称获取表的元数据信息
ResultSet rs=ps.executeQuery();
ResultSetMetaData rsmd= rs.getMetaData();
int len=rsmd.getColumnCount();//獲取列數
for(int i=1;i<=len;i++){
String columnName=rsmd.getColumnName(i);//獲取列名稱
String typeName=rsmd.getColumnTypeName(i);//獲取列的類型名稱
System.out.println(columnName+"\t"+typeName);
}

SQLException

调用JDBC API方法时经常会有一个受检型异常/非运行时异常,必须在编码过程中针对异常进行处理。但是大部分出现的异常是不能通过编码解决,例如SQL语句语法错误、关闭Connection对象时出错。而且SQLException的颗粒度太粗,不能明确表达异常的原因。

所以常见的处理方案有2种:1、向上抛出异常或者记录报错信息。2、将SQLException转换为运行时异常,由上层调用方进行处理

XxxDAO

使用BaseDaoImpl实现具体类的增删改查

create table tb_user(
id bigint primary key auto_increment,
username varchar(20) not null unique,
password varchar(20) not null
)engine=innodb default charset utf8;

根据对应的表结构定义实体类

  • 注意规则:类名称和表名称对应,属性名称和字段名称对应
  • 类中的属性不要使用简单类型,例如long
    • 判断的需要
    • setObject
public class User implements Serializable{
private Long id;
private String username;
private String password;
}

定义对应的接口

public interface IUserDao extends IBaseDao<User>{
//如果有userDao中需要添加的特殊方法,声明在这里
}

定义对应的实现类

public class UserDaoImpl extends BaseDaoImpl<User> implements IUserDao{
//如果有特殊方法,则在这里实现,实际上通用的CRUD方法已经从BaseDao中继承
}

定义工厂类用于创建具体的实现类对象

public class DaoFactory{
public static IUserDao getUserDao(){
return new UserDaoImpl();
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值