带泛型的BaseDAO封装与使用
2022-02-19 本文已影响0人
程序员汪汪
什么是DAO?
-
DAO
:Data Access Object
访问数据信息的类和接口,包括了对数据的CRUD,而不包含任何业务相关的信息。 - 作用:为了实现功能的模块化,更有利于代码的维护和升级。
在实际开发中,DAO
层主要做的是数据持久层的工作,简单说就是和数据库打交道的。针对每张表都会创建相应的xxxDAO
类来实现,由于每张表都会有很多相似的CRUD操作,这些都是重复代码,这时就可以对这些代码进行抽取,封装成BaseDAO
,之后使用,只需继承BaseDAO
,即可使用通用的CRUD操作。
BaseDAO的封装与使用
BaseDAO
的封装:
/**
* DAO:data(base) access object
* 封装了针对于数据表的通用的操作
*/
public abstract class BaseDAO<T> {
// 定义一个变量来接收泛型的类型
private Class<T> clazz = null;
// public BaseDAO(){
//
// }
// 这个代码块中的内容也可以放在上面的构造函数中
{
// 获取父类的类型,这里的this是子类对象
// getGenericSuperclass():用来获取当前类的父类的类型,如果是带泛型的,
// 则返回的type对象必须准确反映泛型参数的实际类型
Type genericSuperclass = this.getClass().getGenericSuperclass();
// ParameterizedType:表示参数化类型
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
// 获取父类的泛型参数
Type[] typeArguments = paramType.getActualTypeArguments();
// 获取第一个泛型参数,这里我们只用了一个泛型
clazz = (Class<T>) typeArguments[0];
}
//通用的增删改操作 ---- version 2.0
public int update(Connection conn, String sql, Object ...args) {
PreparedStatement ps = null;
try {
// 1. 预编译sql语句,返回PreparedStatement的实例
ps = conn.prepareStatement(sql);
// 2. 填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
// 3. 执行
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 4. 关闭资源
JDBCUtils.closeResouse(null, ps);
}
return 0;
}
// 不同表的通用查询操作,返回表中的一条记录(version 2.0 考虑上事务)
public T getBean(Connection conn, String sql, Object... args) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
if (rs.next()) {
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
Object columnValue = rs.getObject(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columnValue);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResouse(null, ps, rs);
}
return null;
}
// 不同表的通用查询操作,返回表中的多条记录构成的集合 version2.0 考虑事务
public List<T> getBeanForList(Connection conn, String sql, Object... args) {
List<T> list = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
list = new ArrayList<>();
while (rs.next()) {
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
Object columnValue = rs.getObject(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columnValue);
}
list.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResouse(null, ps, rs);
}
return null;
}
/**
* 用于查询特殊值的通用方法,例如select count(*)...这样的sql语句
*/
public <E> E getValue(Connection conn, String sql, Object... args) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
rs = ps.executeQuery();
if (rs.next()) {
return (E) rs.getObject(1);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JDBCUtils.closeResouse(null, ps, rs);
}
return null;
}
}
主要的难点在于怎么获得泛型参数的真实类型。
CustomerDAO
接口:
/**
* @Description 此接口用于规范针对于customers表的常用操作
*/
public interface CustomerDAO {
/**
* 将Customer对象添加到数据库中
* @param conn
* @param cust
*/
void insert(Connection conn, Customer cust);
/**
* 针对指定的id,删除表中的一条记录
* @param conn
* @param id
*/
void deleteById(Connection conn, int id);
/**
* 针对内存中过的cust对象,去修改数据表中指定的记录
* @param conn
* @param cust
*/
void update(Connection conn, Customer cust);
/**
* 针对指定的id查询得到对应的Customer对象
* @param conn
* @param id
*/
Customer getCustomerById(Connection conn, int id);
/**
* 查询表中的所有记录构成的集合
* @param conn
* @return
*/
List<Customer> getAll(Connection conn);
/**
* 返回数据表中的条目数
* @param conn
* @return
*/
Long getCount(Connection conn);
/**
* 返回数据表中最大的生日
* @param conn
* @return
*/
Date getMaxBirth(Connection conn);
}
CustomerDAOImpl
:
public class CustomerDAOImpl extends BaseDAO<Customer> implements CustomerDAO {
@Override
public void insert(Connection conn, Customer cust) {
String sql = "insert into customers(name, email, birth) values(?,?,?)";
update(conn, sql, cust.getName(), cust.getEmail(), cust.getBirth());
}
@Override
public void deleteById(Connection conn, int id) {
String sql = "delete from customers where id = ?";
update(conn, sql, id);
}
@Override
public void update(Connection conn, Customer cust) {
String sql = "update customers set name = ?, email = ?, birth = ? where id = ?";
update(conn, sql, cust.getName(), cust.getEmail(), cust.getBirth(), cust.getId());
}
@Override
public Customer getCustomerById(Connection conn, int id) {
String sql = "select id, name, email, birth from customers where id = ?";
Customer customer = getBean(conn, sql, id);
return customer;
}
@Override
public List<Customer> getAll(Connection conn) {
String sql = "select id, name, email, birth from customers";
List<Customer> list = getBeanForList(conn, sql);
return list;
}
@Override
public Long getCount(Connection conn) {
String sql = "select count(*) from customers";
return getValue(conn, sql);
}
@Override
public Date getMaxBirth(Connection conn) {
String sql = "select max(birth) from customers";
return getValue(conn, sql);
}
}
Customer类:
// get、set,有参和无参构造以及toString方法自行补齐
public class Customer {
private int id;
private String name;
private String email;
private Date birth;
测试代码:
class CustomerDAOImplTest {
private CustomerDAOImpl dao = new CustomerDAOImpl();
@org.junit.jupiter.api.Test
void insert() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
Customer customer = new Customer(1, "冯宝宝", "bb@163.com", new Date(464234678L));
dao.insert(conn, customer);
System.out.println("添加成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResouse(conn, null);
}
}
@org.junit.jupiter.api.Test
void deleteById() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
dao.deleteById(conn, 19);
System.out.println("删除成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResouse(conn, null);
}
}
@org.junit.jupiter.api.Test
void update() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
Customer customer = new Customer(5, "哪吒", "nezha@163.com", new Date(165461346L));
dao.update(conn, customer);
System.out.println("修改成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResouse(conn, null);
}
}
@org.junit.jupiter.api.Test
void getCustomerById() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
Customer customer = dao.getCustomerById(conn, 5);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResouse(conn, null);
}
}
@org.junit.jupiter.api.Test
void getAll() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
List<Customer> list = dao.getAll(conn);
list.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResouse(conn, null);
}
}
@org.junit.jupiter.api.Test
void getCount() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
Long count = dao.getCount(conn);
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResouse(conn, null);
}
}
@org.junit.jupiter.api.Test
void getMaxBirth() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
Date maxBirth = dao.getMaxBirth(conn);
System.out.println(maxBirth);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResouse(conn, null);
}
}
}
如果对你有帮助,点个赞呗,关注公众号程序员汪汪
,一起探讨更多Java问题!