JDBC的DAO形式

本文介绍了如何使用Java JDBC实现DAO(数据访问对象)模式,包括BaseDAO抽象类的设计,自定义CRUD操作,以及针对Customer表的CustomerDAO接口和实现。BaseDAO提供了通用的查询和修改方法,CustomerDAO实现了增删改查功能,并通过JUnit4进行了测试。
摘要由CSDN通过智能技术生成

前言

把最统一的查询和修改(统一增删更新)操作封装到BaseDAO抽象类中,其它表操作可以通过继承该抽象类来实现自定义的CRUD操作。

一、BaseDAO抽象类

package com.xhu.java.jdbc.dao;

import com.xhu.java.jdbc.JDBCUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @function 通用功能,如查询一个或多个,修改操作,其它操作如聚集函数
 */
public abstract class BaseDAO<T> {
    private Class<T> c = null;
    //获取BaseDAO子类所继承父类BaseDAO时所给的实际泛型类型。毕竟只能new BaseDAO的子类,这里的this必然指BaseDAO子类对象。这个抽象类无法new出对象
    {
        Type genericSuperclass = this.getClass().getGenericSuperclass();
        ParameterizedType paramT = (ParameterizedType) genericSuperclass;
        c = (Class<T>) paramT.getActualTypeArguments()[0];
    }

    /**
     * @param conn 一个事务的连接
     * @param sql
     * @param args
     * @return
     * @throws Exception
     * @function 获取多条记录, 通用与所有类型
     */
    public List<T> getMultiInstance(Connection conn, String sql, Object... args) {
        //1.初始化
        PreparedStatement ps = null;
        ResultSet res = null;
        //返回结果
        List<T> resList = new ArrayList<>();
        try {
            //2.获取预处理SQL对象
            ps = conn.prepareStatement(sql);
            //3.占位符赋值
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            //4.执行SQL
            res = ps.executeQuery();
            //5.处理结果集
            /**
             * @Reflect
             * res将查询出数据的字段数据即元数据信息封装在Meta-Data中
             * 获取元数据,再获取查询的列数以及字段名
             * 通过res获取字段的对应值
             * 通过反射+字段名把对应值动态注入进去
             */

            while (res.next()) {
                ResultSetMetaData metaData = res.getMetaData();
                int cCount = metaData.getColumnCount();
                T t = c.getConstructor(null).newInstance();
                //反射注入需要的class对象
                Class cusC = t.getClass();
                for (int i = 0; i < cCount; i++) {
                    //获取字段名
                    String columnName = metaData.getColumnLabel(i + 1);//获取别名对应POJO类,如果没有别名就是原名
                    Object columnValue = res.getObject(i + 1);
                    //反射实现动态注入数据
                    //获取任意权限的字段
                    Field field = cusC.getDeclaredField(columnName);
                    //获取private的权限
                    field.setAccessible(true);
                    //设置属性值
                    field.set(t, columnValue);
                }
                resList.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //6.关闭资源,用于事务,不能关闭连接资源,让所有SQL处理串在一个连接里面。
            JDBCUtils.closeQuery(ps, null, res);
        }

        //7.返回查询结果
        return resList;
    }

    /**
     * @param conn 一个事务的连接
     * @param sql
     * @param args
     * @return T
     * @throws Exception
     * @function 各种类的通用查询
     */
    public T getInstance(Connection conn, String sql, Object... args) {
        //1.不用获取对象,传入一个事务的conn
        //2.获取预处理SQL对象
        PreparedStatement ps = null;
        ResultSet res = null;
        T t = null;
        try {
            ps = conn.prepareStatement(sql);
            //3.占位符赋值
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            //4.执行SQL
            res = ps.executeQuery();
            //5.处理结果集
            /**
             * @Reflect
             * res将查询出数据的字段数据即元数据信息封装在Meta-Data中
             * 获取元数据,再获取查询的列数以及字段名
             * 通过res获取字段的对应值
             * 通过反射+字段名把对应值动态注入进去
             */
            if (res.next()) {
                ResultSetMetaData metaData = res.getMetaData();
                int cCount = metaData.getColumnCount();
                t = c.getConstructor(null).newInstance();
                //反射注入需要的class对象
                Class cusC = t.getClass();
                for (int i = 0; i < cCount; i++) {
                    //获取字段名
                    String columnName = metaData.getColumnLabel(i + 1);//获取别名对应POJO类,如果没有别名就是原名
                    Object columnValue = res.getObject(i + 1);
                    //反射实现动态注入数据
                    String setMethodName = "set" + (char) (columnName.charAt(0) - 32) + columnName.substring(1);
                    String getMethodName = "get" + (char) (columnName.charAt(0) - 32) + columnName.substring(1);
                    Method method = cusC.getDeclaredMethod(setMethodName, cusC.getDeclaredMethod(getMethodName, null).getReturnType());
                    method.invoke(t, columnValue);
                    /**
                     * 方式二
                     * //获取任意权限的字段
                     * Field field = cusC.getDeclaredField(columnName);
                     * //获取private的权限
                     * field.setAccessible(true);
                     * //设置属性值
                     * field.set(cus, columnName);
                     */

                }
            }
        } catch (Exception throwables) {
            throwables.printStackTrace();
        } finally {
            //6.关闭资源,将一个事务的SQL串在一个连接里,不能关闭SQL
            JDBCUtils.closeQuery(ps, null, res);
        }
        //7.返回查询结果
        return t;
    }

    /**
     * @param conn 一个事务的连接
     * @param sql  要执行的SQL语句
     * @param args SQL中要填充的参数
     * @function 增删改统一操作
     */
    public void update(Connection conn, String sql, Object... args) {
        //1.初始化
        PreparedStatement ps = null;
        try {
            //2.通过连接+sql得到一个把SQL语句预编译的操作SQL对象PreparedStatement
            ps = conn.prepareStatement(sql);
            //3.为预编译的SQL中占位符设置数值
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            //4.执行SQL
            ps.execute();
        } catch (Exception e) {
            System.out.println("插入异常");
            e.printStackTrace();
        } finally {
            //5.关闭连接,连接资源不可关闭,将所有SQL串在一个连接中。
            JDBCUtils.close(ps, null);
        }
    }

    /**
     * @param conn
     * @param sql
     * @param args
     * @param <T>
     * @return
     * @function 用于获取聚集函数的值
     */
    public <T> T getValue(Connection conn, String sql, Object... args) {
        PreparedStatement ps = null;
        ResultSet res = null;
        try {
            //1.获取操作SQL对象
            ps = conn.prepareStatement(sql);
            //2.设置参数
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            //3.执行SQL并获取结果集
            res = ps.executeQuery();
            //4.处理结果集
            if (res.next()) {
                return (T) res.getObject(1);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.closeQuery(ps, null, res);
        }
        return null;
    }

}

二、自定义CRUD

1、Customer

package com.xhu.java.jdbc.pojo;

import java.sql.Date;

/*
 * ORM编程思想  (object relational mapping)
 * 一个数据表对应一个java类
 * 表中的一条记录对应java类的一个对象
 * 表中的一个字段对应java类的一个属性
 * 
 */
public class Customer {
	
	private int id;
	private String name;
	private String email;
	private Date birth;
	public Customer() {
		super();
	}
	public Customer(int id, String name, String email, Date birth) {
		super();
		this.id = id;
		this.name = name;
		this.email = email;
		this.birth = birth;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public Date getBirth() {
		return birth;
	}
	public void setBirth(Date birth) {
		this.birth = birth;
	}
	@Override
	public String toString() {
		return "Customer [id=" + id + ", name=" + name + ", email=" + email + ", birth=" + birth + "]";
	}
	
	
	
}

2、CustomerDAO接口

package com.xhu.java.jdbc.dao;

import com.xhu.java.jdbc.pojo.Customer;

import java.sql.Connection;
import java.sql.Date;
import java.util.List;

/**
 * @definition 定义Customer表的一组规范。
 */
public interface CustomerDAO {
    /**
     * @param conn
     * @param cus
     * @definition 定义增加
     */
    void insert(Connection conn, Customer cus);

    /**
     * @param conn
     * @param id
     * @dfinition 定义删除操作,根据id删除一条记录
     */
    void delete(Connection conn, int id);

    /**
     * @param conn
     * @param cus
     * @definition 定义修改操作,根据cus中的id来修改一条记录。
     */
    void update(Connection conn, Customer cus);

    /**
     * @param conn
     * @param id
     * @return
     * @definition 定义获取一个指定的Customer,根据id来获取
     */
    Customer getCustomerById(Connection conn, int id);

    /**
     * @param conn
     * @return
     * @definition 定义获取所有Customer
     */
    List<Customer> getAll(Connection conn);

    /**
     * @param conn
     * @return
     * @function 获取一共多少条记录
     */
    long getCount(Connection conn);

    /**
     * @param conn
     * @return
     * @function 获取谁最晚出生
     */
    Date getMaxbirth(Connection conn);
}

3、DAO实现

package com.xhu.java.jdbc.dao.impl;

import com.xhu.java.jdbc.dao.BaseDAO;
import com.xhu.java.jdbc.dao.CustomerDAO;
import com.xhu.java.jdbc.pojo.Customer;

import java.sql.Connection;
import java.sql.Date;
import java.util.List;

public class CustomerDAOImpl extends BaseDAO<Customer> implements CustomerDAO {
    @Override
    public void insert(Connection conn, Customer cus) {
        String sql = "insert into customers(`name`,email,birth) values(?,?,?)";
        update(conn, sql, cus.getName(), cus.getEmail(), cus.getBirth());
    }

    @Override
    public void delete(Connection conn, int id) {
        String sql = "delete from customers where id = ?";
        update(conn, sql, id);
    }

    @Override
    public void update(Connection conn, Customer cus) {
        String sql = "update customers set `name` = ?,email = ?,birth = ? where id = ?";
        update(conn, sql, cus.getName(), cus.getEmail(), cus.getBirth(), cus.getId());
    }

    @Override
    public Customer getCustomerById(Connection conn, int id) {
        String sql = "select id,`name`,email,birth from customers where id = ?";
        return getInstance(conn, sql, id);
    }

    @Override
    public List<Customer> getAll(Connection conn) {
        String sql = "select id,`name`,email,birth from customers";
        return getMultiInstance(conn, sql);
    }

    @Override
    public long getCount(Connection conn) {
        String sql = "select count(1) from customers";
        return getValue(conn, sql);
    }

    @Override
    public Date getMaxbirth(Connection conn) {
        String sql = "select max(birth) from customers";
        return getValue(conn, sql);
    }
}

4、Junit4测试

package test.com.xhu.java.jdbc.dao.impl;

import com.xhu.java.jdbc.JDBCUtils;
import com.xhu.java.jdbc.dao.impl.CustomerDAOImpl;
import com.xhu.java.jdbc.pojo.Customer;
import org.junit.Test;
import org.junit.Before;
import org.junit.After;

import java.sql.Connection;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.List;

/**
 * CustomerDAOImpl Tester.
 *
 * @author <Authors name>
 * @version 1.0
 * @since <pre>11 29, 2021</pre>
 */
public class CustomerDAOImplTest {
    private CustomerDAOImpl dao = new CustomerDAOImpl();
    private Connection conn = null;

    @Before
    public void before() throws Exception {
    }

    @After
    public void after() throws Exception {
    }

    /**
     * Method: insert(Connection conn, Customer cus)
     */
    @Test
    public void testInsert() throws Exception {
        conn = JDBCUtils.getConn();
        dao.insert(conn, new Customer(1, "李某", "lm@qq.com", new Date(new SimpleDateFormat("yyyy-MM-dd").parse("1998-9-9").getTime())));
        JDBCUtils.close(null, conn);
    }

    /**
     * Method: delete(Connection conn, int id)
     */
    @Test
    public void testDelete() throws Exception {
        conn = JDBCUtils.getConn();
        dao.delete(conn, 20);
        JDBCUtils.close(null, conn);
    }

    /**
     * Method: update(Connection conn, Customer cus)
     */
    @Test
    public void testUpdate() throws Exception {
        conn = JDBCUtils.getConn();
        dao.update(conn, new Customer(20, "王某", "wm@qq.com", new Date(new SimpleDateFormat("yyyy-MM-dd").parse("1998-9-9").getTime())));
        JDBCUtils.close(null, conn);
    }

    /**
     * Method: getCustomerById(Connection conn, int id)
     */
    @Test
    public void testGetCustomerById() throws Exception {
        conn = JDBCUtils.getConn();
        Customer cus = dao.getCustomerById(conn, 1);
        System.out.println(cus);
        JDBCUtils.close(null, conn);
    }

    /**
     * Method: getAll(Connection conn)
     */
    @Test
    public void testGetAll() throws Exception {
        conn = JDBCUtils.getConn();
        List<Customer> cus = dao.getAll(conn);
        cus.forEach(System.out::println);
        JDBCUtils.close(null, conn);
    }

    /**
     * Method: getCount(Connection conn)
     */
    @Test
    public void testGetCount() throws Exception {
        conn = JDBCUtils.getConn();
        long count = dao.getCount(conn);
        System.out.println(count);
        JDBCUtils.close(null, conn);
    }

    /**
     * Method: getMaxbirth(Connection conn)
     */
    @Test
    public void testGetMaxbirth() throws Exception {
        conn = JDBCUtils.getConn();
        Date date = dao.getMaxbirth(conn);
        System.out.println(date);
        JDBCUtils.close(null, conn);
    }


} 

总结

1)BaseDAO抽象类封装公共操作
2)各个表的DAO自定义CRUD
3)Junnit4测试,setting中plugins install JunitGuide,然后右键类generate Test类。

参考文献

[1] JDBC 尚硅谷(含SQL文件和各种资料)
[2] 自动生成测试类 百度知道
[3] Idea 添加Junit4的三种方法

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值