[JDBC]基于三层架构和MVC架构的JDBCTools

0.三层架构和MVC架构

0.1DAO是什么

DAO 是 Java 分层开发中专门负责和数据库打交道的层 ,核心作用是:把所有数据库的增删改查(CRUD)操作封装起来,让业务层(比如你包中的 BAO/Service)不用关心数据库连接、SQL 编写、结果集处理等细节,只专注于业务逻辑

0.2bean

0.2.1Department

复制代码
package bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Department {
    private int did;
    private String dname;
    private String description;
    //构造器,get/set,toString,equals和hashCode

}

0.2.2Employee

复制代码
package bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Employee {
    private Integer eid;
    private String ename;
    private Double salary;
    //    private double commissionPct;
    private BigDecimal commissionPct;
    private Date birthday;
    //    private char gender;
    private String gender;
    private String tel;
    private String email;
    private String address;
    private String workPlace;
    private Date hiredate;
    private Integer jobId;
    private Integer mid;
    private Integer did;

    public Employee(int eid, String ename, double salary) {
        this.eid = eid;
        this.ename = ename;
        this.salary = salary;
    }
}

0.3DAO

0.3.1接口:DepartmentDAO

复制代码
package DAO;
//引入bean文件夹下的

import bean.Department;

import java.util.ArrayList;

public interface DepartmentDAO {
    //接口里面定义的方法,就是你要对部门对象和部门表做哪些对象(增、删、改、查)
    int insert(Department department);//insert方法负责把一个部门对象,存储到t_department表
    int update(Department department);//update方法负责把一个部门对象的信息,覆盖t_department表的一条记录
    //大家默认为主键id是不变的,department对象中的did用于定位一条记录,剩余的属性 覆盖 这条记录的其他字段值
    int delete(int did);//更常见一些
    int delete(String dname);
    ArrayList<Department> getAllDepartments();
}

0.3.2接口:EmployeeDAO

复制代码
package DAO;

import bean.Employee;

import java.util.ArrayList;

public interface EmployeeDAO {
    int insert(Employee employee);
    int update(Employee employee);//主键eid不变
    int delete(int eid);
    ArrayList<Employee> getAllEmployees();
}

0.3.3实现类:DepartmentDAOImpl

复制代码
package DAO;

import BAO.BaseDaoThree;
import bean.Department;

import java.sql.SQLException;
import java.util.ArrayList;

public class DepartmentDAOImpl implements DepartmentDAO {
    @Override
    public int insert(Department department) {
        try {
            //t_department表中did自增(提醒大家对你操作的表的结构,包括字段、约束必须清楚)
            String sql = "insert into t_department values(null,?,?)";
            int len = BaseDaoThree.update(sql, department.getDname(), department.getDescription());
            return len;
        } catch (SQLException e) {
            //把编译时类型的异常,包装为运行时类型的异常,异常没有真正处理,仍然扔出去了,编译器不报错了
            throw new RuntimeException(e);
        }
    }

    @Override
    public int update(Department department) {
        String sql = "update t_department set dname=?, description=? where did = ?";
        try {
            int len = BaseDaoThree.update(sql, department.getDname(), department.getDescription(),department.getDid());
            return len;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int delete(int did) {
        String sql = "delete from t_department where did = ?";
        try {
            int len = BaseDaoThree.update(sql, did);
            return len;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int delete(String dname) {
        String sql = "delete from t_department where dname = ?";
        try {
            int len = BaseDaoThree.update(sql, dname);
            return len;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public ArrayList<Department> getAllDepartments() {
        String sql = "select * from t_department";
        try {
            ArrayList<Department> list = BaseDaoThree.queryList(Department.class, sql);
            return list;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

0.3.4实现类:EmployeeDAOImpl

复制代码
package DAO;

import BAO.BaseDaoThree;
import bean.Employee;

import java.sql.SQLException;
import java.util.ArrayList;

public class EmployeeDAOImpl implements EmployeeDAO {
    @Override
    public int insert(Employee employee) {
        //eid是自增的
        String sql = """
                    INSERT INTO t_employee(`eid`,`ename`,`salary`,`commission_pct`,
                    `birthday`,`gender`,`tel`,`email`,`address`,
                    `work_place`,`hiredate`,`job_id`,`mid`,`did`)
                    VALUES(NULL,?,?,?,?,?,?,?,?,?,?,?,?,?);
                """;//文本块
        try {
            int len = BaseDaoThree.update(sql, employee.getEname(),
                    employee.getSalary(),
                    employee.getCommissionPct(),
                    employee.getBirthday(),
                    employee.getGender(),
                    employee.getTel(),
                    employee.getEmail(),
                    employee.getAddress(),
                    employee.getWorkPlace(),
                    employee.getHiredate(),
                    employee.getJobId(),
                    employee.getMid(),
                    employee.getDid());
            return len;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int update(Employee employee) {
        //eid不变
        String sql = """
                update t_employee set `ename`=?,`salary`=?,`commission_pct`=?,`birthday`=?,`gender`=?,`tel`=?,`email`=?,
                `address`=?,`work_place`=?,`hiredate`=?,`job_id`=?,`mid`=?,`did`=? where `eid`=?;
                """;
        try {
            int len = BaseDaoThree.update(sql, employee.getEname(),
                    employee.getSalary(),
                    employee.getCommissionPct(),
                    employee.getBirthday(),
                    employee.getGender(),
                    employee.getTel(),
                    employee.getEmail(),
                    employee.getAddress(),
                    employee.getWorkPlace(),
                    employee.getHiredate(),
                    employee.getJobId(),
                    employee.getMid(),
                    employee.getDid(),
                    employee.getEid());
            return len;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int delete(int eid) {
        String sql = "delete from t_employee where eid = ?";
        try {
            int len = BaseDaoThree.update(sql, eid);
            return len;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public ArrayList<Employee> getAllEmployees() {
        //String sql = "select * from t_employee";
        String sql = """
                    SELECT `eid`,`ename`,`salary`,
                    `commission_pct` AS commissionPct,
                    `birthday`,`gender`,`tel`,`email`,`address`,
                    `work_place` AS workPlace,`hiredate`,
                    `job_id` AS jobId,`mid`,`did` FROM t_employee;
                """;
        try {
            ArrayList<Employee> list = BaseDaoThree.queryList(Employee.class, sql);
            return list;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

0.4BaseDAO

0.4.1BaseDAOThree

复制代码
package BAO;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;

public class BaseDaoThree { //最终版
    //通用的增、删、改功能
    public static int update(String sql, Object... args) throws SQLException {
        //1、获取连接
        Connection connection = JDBCUtilTwo.getConnection();
        //2、准备sql(通过参数传入)

        //3、创建PreparedStatement对象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //4、设置?
        for(int i=1; i<=args.length; i++){
            preparedStatement.setObject(i, args[i-1]);
        }
        //5、调用 PreparedStatement对象.executeUpdate()
        int len = preparedStatement.executeUpdate();
        //6、释放资源
        preparedStatement.close();
//        JDBCUtilOne.freeConnection(connection);//不关闭,如果关闭了,同一个事务的其他sql用不了了
        return len;
    }

    //通用的查询功能
    //第一个参数可以设置为Class clazz,它代表 这个查询结果的T的实际类型,T可能代表Employee,Department,Order....
    //第一个参数也可以设置为String className,  T的具体类型名 com.atguigu.bean.Employee等
    public static <T> ArrayList<T> queryList(Class<T> clazz, String sql, Object... args ) throws Exception {
        //1、获取连接
        Connection connection = JDBCUtilTwo.getConnection();
        //2、准备sql(通过参数传入)

        //3、创建PreparedStatement对象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //4、设置?
        for(int i=1; i<=args.length; i++){
            preparedStatement.setObject(i, args[i-1]);
        }
        //5、调用 PreparedStatement对象.executeQuery()
        ResultSet resultSet = preparedStatement.executeQuery();
        ResultSetMetaData metaData = resultSet.getMetaData();//获取结果集的元数据
        int columnCount = metaData.getColumnCount();

        //怎么把结果集的数据 变为 一组对象,放到 ArrayList集合中返回
        ArrayList<T> result = new ArrayList<>();
        //6、遍历resultSet
        while(resultSet.next()){//while循环循环一次,代表一行,一行代表一个对象
            //(1)创建对象
            //获取无参构造
            Constructor<T> constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);//以防这个构造器不是公共的
            //new对象
            T t = constructor.newInstance();

            //(2)设置属性
            for(int i=1; i<=columnCount; i++) {//每一次for循环代表一个属性
//                String columnName = metaData.getColumnName(i);//getColumnName获取列的原名称
                String columnName = metaData.getColumnLabel(i);//getColumnLabel获取列的别名或原名
                //获取某个属性对应的Fieid对象
                Field field = clazz.getDeclaredField(columnName);
                //通常属性私有化
                field.setAccessible(true);
                //设置值
                field.set(t, resultSet.getObject(i));
            }

            //添加t到集合中
            result.add(t);
        }

        return result;
    }

}

0.4.2JDBCUtilTwo

复制代码
package BAO;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class JDBCUtilTwo {//最终版
    private static DataSource ds;
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    static {
        try {
            //静态代码块,在类加载和初始化时执行
            Properties properties = new Properties();
            properties.load(JDBCUtilTwo.class.getClassLoader().getResourceAsStream("druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        Connection connection = threadLocal.get();//比喻,某个线程到自己的背包map中获取(threadLocal,value)值
        if(connection == null){//如果是空的,说明这个线程还没有获取过连接
            connection = ds.getConnection();
            threadLocal.set(connection);
        }
        //如果if不成立,说明这个线程之前已经拿过连接了,已经放入背包了,直接返回之前的连接对象即可
        return connection;
    }

    public static void freeConnection(){
        Connection connection = threadLocal.get();//比喻,某个线程到自己的背包map中获取(threadLocal,value)值
        if(connection != null){
            try {
                threadLocal.remove();//从背包中删除,当前线程就没有这个连接了
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

0.5BaseDAO和DAO的区别

类型 BaseDAO(基础类) DepartmentDAO(业务 DAO)
核心定位 DAO 层的 "通用工具父类" DAO 层的 "业务实现类"
封装的逻辑 所有 DAO 都需要的通用操作(获取连接、关闭资源、通用 CRUD、分页) 针对特定表的专属 CRUD(查部门、新增部门)
能否直接使用 不能直接 new,只能被其他 DAOImpl 继承 可直接实例化 / 调用(如 new DepartmentDAOImpl ())
方法特点 泛型 / 通用方法(如 save(Object obj) 专属方法(如 findDepartmentById(int did)

一.基于druid的通用连接

1.1图示:

1.2code:

复制代码
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class JDBCConnectionTool  {
    private static DataSource ds;
    static {
        try {
            //静态代码块,在类加载和初始化时执行
            Properties properties = new Properties();
            properties.load(testConnection.class.getClassLoader().getResourceAsStream("druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    public static void freeConnection(Connection connection){
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

=========================================================================

复制代码
import org.junit.jupiter.api.Test;

import java.sql.Connection;

public class testConnection {
    @Test
    public void testConnection()throws  Exception {
        Connection conn = JDBCConnectionTool.getConnection();
        System.out.println(conn);
    }
}

二.通用的增

2.1Department

复制代码
@Override
public int insert(Department department) {
    try {
        //t_department表中did自增(提醒大家对你操作的表的结构,包括字段、约束必须清楚)
        String sql = "insert into t_department values(null,?,?)";
        int len = BaseDaoThree.update(sql, department.getDname(), department.getDescription());
        return len;
    } catch (SQLException e) {
        //把编译时类型的异常,包装为运行时类型的异常,异常没有真正处理,仍然扔出去了,编译器不报错了
        throw new RuntimeException(e);
    }
}

2.2Employee

复制代码
@Override
public int insert(Employee employee) {
    //eid是自增的
    String sql = """
                INSERT INTO t_employee(`eid`,`ename`,`salary`,`commission_pct`,
                `birthday`,`gender`,`tel`,`email`,`address`,
                `work_place`,`hiredate`,`job_id`,`mid`,`did`)
                VALUES(NULL,?,?,?,?,?,?,?,?,?,?,?,?,?);
            """;//文本块
    try {
        int len = BaseDaoThree.update(sql, employee.getEname(),
                employee.getSalary(),
                employee.getCommissionPct(),
                employee.getBirthday(),
                employee.getGender(),
                employee.getTel(),
                employee.getEmail(),
                employee.getAddress(),
                employee.getWorkPlace(),
                employee.getHiredate(),
                employee.getJobId(),
                employee.getMid(),
                employee.getDid());
        return len;
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

三.通用的删

3.1Department

复制代码
@Override
public int delete(int did) {
    String sql = "delete from t_department where did = ?";
    try {
        int len = BaseDaoThree.update(sql, did);
        return len;
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

3.2Employee

复制代码
@Override
public int delete(int eid) {
    String sql = "delete from t_employee where eid = ?";
    try {
        int len = BaseDaoThree.update(sql, eid);
        return len;
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

四.通用的改

4.1Department

复制代码
@Override
public int update(Department department) {
    String sql = "update t_department set dname=?, description=? where did = ?";
    try {
        int len = BaseDaoThree.update(sql, department.getDname(), department.getDescription(),department.getDid());
        return len;
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

4.2Employee

复制代码
@Override
public int update(Employee employee) {
    //eid不变
    String sql = """
            update t_employee set `ename`=?,`salary`=?,`commission_pct`=?,`birthday`=?,`gender`=?,`tel`=?,`email`=?,
            `address`=?,`work_place`=?,`hiredate`=?,`job_id`=?,`mid`=?,`did`=? where `eid`=?;
            """;
    try {
        int len = BaseDaoThree.update(sql, employee.getEname(),
                employee.getSalary(),
                employee.getCommissionPct(),
                employee.getBirthday(),
                employee.getGender(),
                employee.getTel(),
                employee.getEmail(),
                employee.getAddress(),
                employee.getWorkPlace(),
                employee.getHiredate(),
                employee.getJobId(),
                employee.getMid(),
                employee.getDid(),
                employee.getEid());
        return len;
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

五.通用的查

5.1Department

复制代码
@Override
public ArrayList<Department> getAllDepartments() {
    String sql = "select * from t_department";
    try {
        ArrayList<Department> list = BaseDaoThree.queryList(Department.class, sql);
        return list;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

5.2Employee

复制代码
@Override
public ArrayList<Employee> getAllEmployees() {
    //String sql = "select * from t_employee";
    String sql = """
                SELECT `eid`,`ename`,`salary`,
                `commission_pct` AS commissionPct,
                `birthday`,`gender`,`tel`,`email`,`address`,
                `work_place` AS workPlace,`hiredate`,
                `job_id` AS jobId,`mid`,`did` FROM t_employee;
            """;
    try {
        ArrayList<Employee> list = BaseDaoThree.queryList(Employee.class, sql);
        return list;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
相关推荐
IT邦德6 小时前
RPM包快速安装Oracle26ai
数据库·oracle
Dovis(誓平步青云)6 小时前
《滑动窗口算法:从 “暴力遍历” 到 “线性高效” 的思维跃迁》
运维·服务器·数据库·算法
mr_LuoWei20096 小时前
python工具:python代码知识库笔记
数据库·python
这周也會开心6 小时前
Redis数据类型的底层实现和数据持久化
数据库·redis·缓存
ん贤6 小时前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
数据知道6 小时前
PostgreSQL 核心原理:系统内部的对象寻址机制(OID 对象标识符)
数据库·postgresql
倔强的石头_7 小时前
关系数据库替换用金仓:数据迁移过程中的完整性与一致性风险
数据库
Elastic 中国社区官方博客7 小时前
使用 Groq 与 Elasticsearch 进行智能查询
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
穿过锁扣的风7 小时前
一文搞懂 SQL 五大分类:DQL/DML/DDL/DCL/TCL
数据库·microsoft·oracle