什么是DAO?
-
DAO
:Data Access Object
訪問數(shù)據(jù)信息的類和接口,包括了對數(shù)據(jù)的CRUD,而不包含任何業(yè)務(wù)相關(guān)的信息迹鹅。 - 作用:為了實(shí)現(xiàn)功能的模塊化担孔,更有利于代碼的維護(hù)和升級江锨。
在實(shí)際開發(fā)中,DAO
層主要做的是數(shù)據(jù)持久層的工作糕篇,簡單說就是和數(shù)據(jù)庫打交道的啄育。針對每張表都會創(chuàng)建相應(yīng)的xxxDAO
類來實(shí)現(xiàn),由于每張表都會有很多相似的CRUD操作拌消,這些都是重復(fù)代碼挑豌,這時就可以對這些代碼進(jìn)行抽取,封裝成BaseDAO
拼坎,之后使用浮毯,只需繼承BaseDAO
,即可使用通用的CRUD操作泰鸡。
BaseDAO的封裝與使用
BaseDAO
的封裝:
/**
* DAO:data(base) access object
* 封裝了針對于數(shù)據(jù)表的通用的操作
*/
public abstract class BaseDAO<T> {
// 定義一個變量來接收泛型的類型
private Class<T> clazz = null;
// public BaseDAO(){
//
// }
// 這個代碼塊中的內(nèi)容也可以放在上面的構(gòu)造函數(shù)中
{
// 獲取父類的類型债蓝,這里的this是子類對象
// getGenericSuperclass():用來獲取當(dāng)前類的父類的類型,如果是帶泛型的盛龄,
// 則返回的type對象必須準(zhǔn)確反映泛型參數(shù)的實(shí)際類型
Type genericSuperclass = this.getClass().getGenericSuperclass();
// ParameterizedType:表示參數(shù)化類型
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
// 獲取父類的泛型參數(shù)
Type[] typeArguments = paramType.getActualTypeArguments();
// 獲取第一個泛型參數(shù)饰迹,這里我們只用了一個泛型
clazz = (Class<T>) typeArguments[0];
}
//通用的增刪改操作 ---- version 2.0
public int update(Connection conn, String sql, Object ...args) {
PreparedStatement ps = null;
try {
// 1. 預(yù)編譯sql語句,返回PreparedStatement的實(shí)例
ps = conn.prepareStatement(sql);
// 2. 填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
// 3. 執(zhí)行
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 4. 關(guān)閉資源
JDBCUtils.closeResouse(null, ps);
}
return 0;
}
// 不同表的通用查詢操作余舶,返回表中的一條記錄(version 2.0 考慮上事務(wù))
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;
}
// 不同表的通用查詢操作啊鸭,返回表中的多條記錄構(gòu)成的集合 version2.0 考慮事務(wù)
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;
}
}
主要的難點(diǎn)在于怎么獲得泛型參數(shù)的真實(shí)類型匿值。
CustomerDAO
接口:
/**
* @Description 此接口用于規(guī)范針對于customers表的常用操作
*/
public interface CustomerDAO {
/**
* 將Customer對象添加到數(shù)據(jù)庫中
* @param conn
* @param cust
*/
void insert(Connection conn, Customer cust);
/**
* 針對指定的id赠制,刪除表中的一條記錄
* @param conn
* @param id
*/
void deleteById(Connection conn, int id);
/**
* 針對內(nèi)存中過的cust對象,去修改數(shù)據(jù)表中指定的記錄
* @param conn
* @param cust
*/
void update(Connection conn, Customer cust);
/**
* 針對指定的id查詢得到對應(yīng)的Customer對象
* @param conn
* @param id
*/
Customer getCustomerById(Connection conn, int id);
/**
* 查詢表中的所有記錄構(gòu)成的集合
* @param conn
* @return
*/
List<Customer> getAll(Connection conn);
/**
* 返回?cái)?shù)據(jù)表中的條目數(shù)
* @param conn
* @return
*/
Long getCount(Connection conn);
/**
* 返回?cái)?shù)據(jù)表中最大的生日
* @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钟些,有參和無參構(gòu)造以及toString方法自行補(bǔ)齊
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);
}
}
}
如果對你有幫助,點(diǎn)個贊唄绊谭,關(guān)注公眾號程序員汪汪
政恍,一起探討更多Java問題!