JDBC 动态查询和程序分层

文章目录

SQL进阶

动态查询: 根据用户给定的条件来决定执行什么样的查询。

代码

/**
     * 根据用户提供的数据进行查询
     * @param departments 封装查询数据的departments对象
     * @return 返回查询到的departments对象容器
     */
private static List<Departments> selectDepartmentsByProperty(Departments departments) {
    Connection conn = null;
    Statement statement = null;
    List<Departments> list = new ArrayList<>();
    ResultSet resultSet = null;
    try {
        conn = DBUtil.getConnection();
        statement = conn.createStatement();
        String sql = genSql(departments);
        resultSet = statement.executeQuery(sql);
        while (resultSet.next()) {
            Departments dept = new Departments();
            dept = new Departments();
            dept.setDepartmentId(resultSet.getInt(1));
            dept.setDepartmentName(resultSet.getString(2));
            dept.setManagerId(resultSet.getInt(3));
            dept.setLocationId(resultSet.getInt(4));
            list.add(dept);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        DBUtil.close(resultSet, statement, conn);
    }
    return list;
}

/**
     * 根据departments对象生成sql查询语句
     * @param departments 封装用户查询数据的departments对象
     * @return 返回生成的sql查询语句
     */
private static String genSql(Departments departments) {
    StringBuilder sql = new StringBuilder("select * from departments where 1=1");
    if (departments.getDepartmentId() != null && departments.getDepartmentId() > 0) {
        sql.append(" and department_id = ").append(departments.getDepartmentId());
    }
    if (departments.getDepartmentName() != null) {
        sql.append(" and department_name = ").append(departments.getDepartmentName());
    }
    if (departments.getLocationId() != null && departments.getLocationId() != 0) {
        sql.append(" and location_id = ").append(departments.getLocationId());
    }
    if (departments.getManagerId() != null && departments.getManagerId() != 0) {
        sql.append(" and manager_id = ").append(departments.getManagerId());
    }
    System.out.println("sql = " + sql);
    return sql.toString();
}

四: 程序的分层使用

1. 什么是应用分层

应用程序通过创建不同的包来实现项目的分层, 将项目中的代码根据功能做具体划分, 并放在不同的包下.

2. 分层的优点

  • 分层结构将应用系统划分为若干层, 每一层只解决问题的一部分, 通过各层的协作
    提供整体解决方案。 大的问题被分解为一系列相对独立的子问题, 局部化在每一层中, 这样
    就有效的降低了单个问题的规模和复杂度, 实现了复杂系统的第一步也是最为关键的一步分
    解。
  • 分层结构具有良好的可扩展性, 为应用系统的演化增长提供了一个灵活的支持, 具
    有良好的可扩展性。 增加新的功能时, 无须对现有的代码做修改, 业务逻辑可以得到最大限
    度的重用。
  • 分层架构易于维护。 在对系统进行分解后, 不同的功能被封装在不同的层中, 层与
    层之间的耦合显著降低。 因此在修改某个层的代码时, 只要不涉及层与层之间的接口, 就不
    会对其他层造成严重影响

3. 三层结构

三层结构就是将整个业务应用划分为: 界面层(User Interface lagyer), 业务逻辑层(business logic Layer), 数据访问层(Date access layer). 区分层次的目的即为了"高内聚, 低耦合"的思想. 在软件体系架构的设计中, 分层结构式最常见, 也是最重要的一种结构.

4. 项目分层图解

JDBC 动态查询和程序分层

5. 分层代码

模型层代码

package pers.jssd.jdbc.pojo;

/**
 * @author jssdjing@gmail.com
 * @create 2019/8/8 15:20
 */
public class Departments {
    private Integer departmentId;
    private String departmentName;
    private Integer managerId;
    private Integer locationId;

    public Departments() {
    }

    public Departments(Integer departmentId, String departmentName, Integer managerId, Integer locationId) {
        this.departmentId = departmentId;
        this.departmentName = departmentName;
        this.managerId = managerId;
        this.locationId = locationId;
    }

    public Integer getDepartmentId() {
        return departmentId;
    }

    public void setDepartmentId(Integer departmentId) {
        this.departmentId = departmentId;
    }

    public String getDepartmentName() {
        return departmentName;
    }

    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }

    public Integer getManagerId() {
        return managerId;
    }

    public void setManagerId(Integer managerId) {
        this.managerId = managerId;
    }

    public Integer getLocationId() {
        return locationId;
    }

    public void setLocationId(Integer locationId) {
        this.locationId = locationId;
    }

    @Override
    public String toString() {
        return "Departments{" +
                "departmentId=" + departmentId +
                ", departmentName='" + departmentName + '\'' +
                ", managerId=" + managerId +
                ", locationId=" + locationId +
                '}';
    }
}

工具层代码

package pers.jssd.jdbc.commons;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ResourceBundle;

/**
 * 数据库连接对象
 *
 * @author jssd
 */
public class DBUtil {

    private static String URL;
    private static String USER;
    private static String PWD;

    static {
        ResourceBundle db = ResourceBundle.getBundle("db");
        String DRIVER = db.getString("driver");
        URL = db.getString("url");
        USER = db.getString("user");
        PWD = db.getString("pwd");
        // 注册驱动
        try {
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 取得连接对象
     *
     * @return 返回连接对象
     */
    public static Connection getConnection() {
        Connection con = null;
        // 取得数据库连接
        try {
            con = DriverManager.getConnection(URL, USER, PWD);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return con;
    }

    /**
     * 关闭资源
     *
     * @param closeable 实现了AutoCloseable的可关闭变量
     */
    public static void close(AutoCloseable... closeable) {
        for (AutoCloseable autoCloseable : closeable) {
            try {
                if (autoCloseable != null) {
                    autoCloseable.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void rollback(Connection conn) {
        try {
            if (conn != null) {
                conn.rollback();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

持久层代码

接口:

package pers.jssd.jdbc.dao;

import pers.jssd.jdbc.pojo.Departments;

import java.util.List;

/**
 * Departments表的持久层接口
 *
 * @author jssdjing@gmail.com
 */
public interface DepartmentsDao {

    /**
     * 通过departments_name查找, 返回一个存储查找数据的容器
     *
     * @param DepartmentName 查找的DepartmentsName
     * @return 返回存储查找数据的容器, 如果没有找到, 则容器size为0
     */
    List<Departments> selectByDepartmentsName(String DepartmentName);

    /**
     * 向Departments表中添加数据
     *
     * @param departments 存储添加数据的departments表
     */
    void InsertDepartments(Departments departments);

}

实现类

package pers.jssd.jdbc.dao.impl;

import pers.jssd.jdbc.commons.DBUtil;
import pers.jssd.jdbc.dao.DepartmentsDao;
import pers.jssd.jdbc.pojo.Departments;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * Departments 持久层的实现类
 *
 * @author jssdjing@gmail.com
 */
public class DepartmentsDaoImpl implements DepartmentsDao {

    @Override
    public List<Departments> selectByDepartmentsName(String departmentName) {
        List<Departments> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        String sql = "select * from departments d where d.department_name = ?";

        try {
            conn = DBUtil.getConnection();
            statement = conn.prepareStatement(sql);
            statement.setString(1, departmentName);
            resultSet = statement.executeQuery();
            while (resultSet.next()) {
                Departments d = new Departments();
                d.setDepartmentId(resultSet.getInt(1));
                d.setDepartmentName(resultSet.getString(2));
                d.setManagerId(resultSet.getInt(3));
                d.setLocationId(resultSet.getInt(4));
                list.add(d);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(resultSet, statement, conn);
        }
        return list;
    }

    @Override
    public void InsertDepartments(Departments departments) {
        Connection conn = null;
        PreparedStatement statement = null;
        String sql = "insert into departments (department_id, department_name, manager_id, location_id) values (default, ?, ?, ?);";
        try {
            conn = DBUtil.getConnection();
            conn.setAutoCommit(false);
            statement = conn.prepareStatement(sql);
            statement.setString(1, departments.getDepartmentName());
            statement.setInt(2, 201);
            statement.setInt(3, 1800);
            statement.execute();
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            DBUtil.rollback(conn);
        } finally {
            DBUtil.close(statement, conn);
        }
    }
}

服务层代码

接口:

package pers.jssd.jdbc.service;

import pers.jssd.jdbc.pojo.Departments;

/**
 * @author jssdjing@gmail.com
 */
public interface DepartmentsService {

    /**
     * 添加一个departments
     * @param departments 要添加的departments
     */
    void addDepartments(Departments departments);
}

实现代码

package pers.jssd.jdbc.service.impl;

import pers.jssd.jdbc.dao.DepartmentsDao;
import pers.jssd.jdbc.dao.impl.DepartmentsDaoImpl;
import pers.jssd.jdbc.pojo.Departments;
import pers.jssd.jdbc.service.DepartmentsService;

/**
 * @author jssdjing@gmail.com
 */
public class DepartmentsServiceImpl implements DepartmentsService {
    @Override
    public void addDepartments(Departments departments) {
        DepartmentsDao departmentsDao = new DepartmentsDaoImpl();
        departmentsDao.InsertDepartments(departments);
    }
}

测试层代码

package pers.jssd.jdbc.test;

import pers.jssd.jdbc.pojo.Departments;
import pers.jssd.jdbc.service.DepartmentsService;
import pers.jssd.jdbc.service.impl.DepartmentsServiceImpl;

/**
 * @author jssdjing@gmail.com
 */
public class TestAddDepartments {
    public static void main(String[] args) {
        DepartmentsService departmentsService = new DepartmentsServiceImpl();
        Departments departments = new Departments(0, "开发部", 0, 0);
        departmentsService.addDepartments(departments);
    }
}

6. 使用BaseDao. 通用SQL模板

新建立一个接口

package pers.jssd.jdbc.dao;

import java.sql.ResultSet;
import java.util.List;

/**
 * @author jssdjing@gmail.com
 */
public interface BaseDao {

    /**
     * 通用DML执行语句
     *
     * @param sql 执行的sql语言
     * @param os 执行的参数数组
     * @return 返回执行成功的条数, 不成功事务会回滚, 返回0条
     */
    int executeUpdate(String sql, Object... os);

    /**
     * 通用DQL执行语句
     *
     * @param sql DQL查询sql
     * @param clz List存储的内容class对象
     * @param os 执行查询的参数数组
     * @param <T> 泛型方法, 传递List存储的内容
     * @return 返回执行成功后存储对象的list
     */
    <T> List<T> executeQuery(String sql, Class<T> clz, Object... os);
}

实现这个接口

package pers.jssd.jdbc.dao.impl;

import org.apache.commons.beanutils.BeanUtils;
import pers.jssd.jdbc.commons.DBUtil;
import pers.jssd.jdbc.dao.BaseDao;
import pers.jssd.jdbc.pojo.Dept;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author jssdjing@gmail.com
 */
public class BaseDaoImpl implements BaseDao {

    @Override
    public int executeUpdate(String sql, Object... os) {
        Connection conn = null;
        PreparedStatement statement = null;
        int count = 0;
        try {
            conn = DBUtil.getConnection();
            conn.setAutoCommit(false);
            statement = conn.prepareStatement(sql);

            // 取得statement执行的sql语句中查询了多少列
            ParameterMetaData metaData = statement.getParameterMetaData();
            for (int i = 0; i < metaData.getParameterCount(); i++) {
                statement.setObject(i + 1, os[i]);
            }
            count = statement.executeUpdate();
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            DBUtil.rollback(conn);
        } finally {
            DBUtil.close(statement, conn);
        }

        return count;
    }

    @Override
    public <T> List<T> executeQuery(String sql, Class<T> clz, Object... os) {
        List<T> list = new ArrayList<>();
        Connection conn = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        try {
            conn = DBUtil.getConnection();
            statement = conn.prepareStatement(sql);

            ParameterMetaData parameterMetaData = statement.getParameterMetaData();
            for (int i = 0; i < parameterMetaData.getParameterCount(); i++) {
                statement.setObject(i + 1, os[i]);
            }
            resultSet = statement.executeQuery();

            ResultSetMetaData metaData = resultSet.getMetaData();
            while (resultSet.next()) {
                T t = clz.newInstance();
                for (int i = 0; i < metaData.getColumnCount(); i++) {
                    String columnName = metaData.getColumnName(i + 1);

                     setValueInObject(t, columnName, resultSet.getObject(i + 1), Class.forName(metaData.getColumnClassName(i + 1)));

                    //BeanUtils.setProperty(t, columnName, resultSet.getObject(i + 1));
                }
                list.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(resultSet, statement, conn);
        }
        return list;
    }

    /**
     * 和BeanUtils一样的效果, 通过反射给对象的属性符值
     */
    private <T> void setValueInObject(T obj, String columnName, Object value, Class<?> columnClassType) {
        Method method;
        try {
            method = obj.getClass().getDeclaredMethod("set" + upperFirstLetter(columnName), columnClassType);
            method.invoke(obj, value);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 首字母大写
     */
    private String upperFirstLetter(String name) {
        char[] cs = name.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }

    public static void main(String[] args) {
        String sql = "insert into departments (department_id, department_name, manager_id, location_id) values (default, ?, ?, ?)";
        String sql2 = "select * from departments d where d.department_name like ?";
        BaseDaoImpl dao = new BaseDaoImpl();
       /* int i = dao.executeUpdate(sql, "调研部2", 204, 2700);
        System.out.println("\"执行了: \" + i + \"次\" = " + "执行了: " + i + "次");*/
        List<Dept> depts = dao.executeQuery(sql2, Dept.class, "%研发%");
        for (Dept dept : depts) {
            System.out.println("dept = " + dept);
        }
    }
}

DepartmentsDaoImol继承此类

package pers.jssd.jdbc.dao.impl;

import pers.jssd.jdbc.dao.DepartmentsDao;
import pers.jssd.jdbc.pojo.Departments;
import pers.jssd.jdbc.pojo.Dept;

import java.util.List;

/**
 * Departments 持久层的实现类
 *
 * @author jssdjing@gmail.com
 */
public class DepartmentsDaoImpl extends BaseDaoImpl implements DepartmentsDao {

    @Override
    public List<Dept> selectByDepartmentsName(String departmentName) {
        String sql = "select * from departments where department_name = ?";
        return this.executeQuery(sql, Dept.class, departmentName);
    }

    @Override
    public void InsertDepartments(Departments departments) {
        // 插入Departments表的sql语句
        String sql = "insert into departments (department_id, department_name, manager_id, location_id) values (default, ?, ?, ?);";
        Object[] os = new Object[]{departments.getDepartmentName(), departments.getManagerId(), departments.getLocationId()};
        int count = this.executeUpdate(sql, os);
        System.out.println("插入执行成功, 共插入了" + count + "条");
    }
}

实体类必须和表名一致

package pers.jssd.jdbc.pojo;

/**
 * @author jssdjing@gmail.com
 */
public class Dept {
    private Integer department_id;
    private String department_name;
    private Integer manager_id;
    private Integer location_id;

    public Dept() {
    }

    public Dept(Integer department_id, String department_name, Integer manager_id, Integer location_id) {
        this.department_id = department_id;
        this.department_name = department_name;
        this.manager_id = manager_id;
        this.location_id = location_id;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "department_id=" + department_id +
                ", department_name='" + department_name + '\'' +
                ", manager_id=" + manager_id +
                ", location_id=" + location_id +
                '}';
    }

    public Integer getDepartment_id() {
        return department_id;
    }

    public void setDepartment_id(Integer department_id) {
        this.department_id = department_id;
    }

    public String getDepartment_name() {
        return department_name;
    }

    public void setDepartment_name(String department_name) {
        this.department_name = department_name;
    }

    public Integer getManager_id() {
        return manager_id;
    }

    public void setManager_id(Integer manager_id) {
        this.manager_id = manager_id;
    }

    public Integer getLocation_id() {
        return location_id;
    }

    public void setLocation_id(Integer location_id) {
        this.location_id = location_id;
    }
}
上一篇:牛客SQL题解-统计各个部门的工资记录数


下一篇:zoomeye学习总结