• Apache-DButils以及Druid(德鲁伊) 多表连接查询的解决方案:两种


    Apache-DButils以及Druid(德鲁伊) 多表连接查询的问题

    在这里插入图片描述


    每博一文案

    张爱玲说,于千万人之中,遇到你所要遇到的人,于千万年之中,时间的无涯的荒野里,没有
    早一步,也没有晚一步,刚巧赶上了。
    人生海海,相遇别离自有时,自然会有人陪你走到最后,但更多的只能陪你走一段路罢了。
    你的一生,我只接一程,再多一分也不能了。王家卫曾说:爱情这东西,时间很关键,认识的太早,或者太晚
    都不行,缘分是很奇妙的东西,有的人明明遇见得很早,却不能一起走到最后。有的人出现时,
    斜风带雨,乱了四季,却早就不是适合相遇的季节了,只能眼睁睁的错过,他早一步春芽不发。
    晚一步错过,正如恰逢其时,这个词,初看温柔又浪漫,再细看还有寻觅和牡丹,要经历
    过多少次的生不逢时,才能换来。如今一生恰逢其时的感慨,每一次的遇见,都是来自上苍的礼物。
    每一份相遇相知,都是属于命运的馈赠,面对离开,只要不辜负相遇就可以了。
    你陪我一程,我念你一生,不管结局如何,至少我们都是真心相待过,这份温度足慰藉余生。
                                           ——————   一禅心灵庙语
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11


    1. 问题描述

    对于多表连接查询,存储多表连接查询的结果集,将 select 查询的结果集,存储到对应的JavaBean 中去的话是不行的 。因为你的查询是基于多张数据表得到的结果集,而对应 映射存储 到只有一张数据表的 一个 JavaBean 当中去,是不行的,该 JavaBean当中只有一张数据表的字段属性值,是无法将 select 基于多张数据表查询到的所有字段值内容,存储到的。

    在这里插入图片描述

    所以我们就可以使用如下两种方式,存储对于 select 多表查询的结果集。

    • 方式一:通过一个JavaBean中附加定义另外一个多表查询的表的 JavaBean 对象
    • 方式二:创建一个新的 JavaBean,该类包含 多表查询的所有字段的属性。

    具体实现如下:解决方案。

    2. 解决方案

    用于方案的讲解,我们需要先创建如下两张数据表 department,employee。执行如下 SQL语句

    CREATE TABLE department(
        dept_id INT PRIMARY KEY AUTO_INCREMENT,
        dept_name VARCHAR(30) NOT NULL DEFAULT '',
        emp_id INT NOT NULL
    );
    
    INSERT INTO department(dept_name,emp_id)
    VALUES('财务部',1),('销售部',2),('研发部',3);
    
    ------------------------------------------
    
    CREATE TABLE employee(
        emp_id INT PRIMARY KEY AUTO_INCREMENT,
        emp_name VARCHAR(30) NOT NULL DEFAULT '',
        email VARCHAR(50) NOT NULL DEFAULT '',
        gender VARCHAR(2) NOT NULL DEFAULT ''
    )
    
    
    INSERT INTO employee(emp_name,email,gender)
    VALUES('张三','zhangsan@126.com','男'),
          ('李四','lisi@126.com','男'),
          ('王五','wangwu@126.com','男');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    在这里插入图片描述

    处理存储如下 SQL语句的 select 多表查询的结果集

    SELECT dept_id AS deptId,dept_name AS deptName,employee.emp_id AS empId, 
                         emp_name AS empName,email,gender  
                         FROM department 
                         JOIN employee 
                         ON employee.emp_id = department.emp_id;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述


    2.1 方案一

    通过创建一个JavaBean 附加上另外一张数据表的 JavaBean 类作为 类属性存在如下:

    在这里插入图片描述

    对于多表连接查询,如果使用BeanListHandler,则会出现其中的一个JavaBean引用类型为 null (如果访问会出现 null引用异常)。也就是这里的 dept 引用类属性的值是 null
    例如 DepartmentDeptAndEmp分类封装为 javabean。DeptAndEmp中声明一个Department的对象。如下图所示:

    在这里插入图片描述

    package Blogs.blogs6;
    
    public class Department {
        private int deptId;
        private String deptName;
        private int empId;
    
    
    
        public Department() {
            // 无参构造器必须,创建用于 apache-dbutls 底层调用使用
        }
    
    
    
        // set/get必须创意用于 apache-dbutls底层反射赋值,取值
       public int getDeptId() {
            return deptId;
        }
    
        public void setDeptId(int deptId) {
            this.deptId = deptId;
        }
    
        public String getDeptName() {
            return deptName;
        }
    
        public void setDeptName(String deptName) {
            this.deptName = deptName;
        }
    
        public int getEmpId() {
            return empId;
        }
    
        public void setEmpId(int empId) {
            this.empId = empId;
        }
    
    
        @Override
        public String toString() {
            return "Department{" +
                    "deptId=" + deptId +
                    ", deptName='" + deptName + '\'' +
                    ", empId=" + empId +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    package Blogs.blogs6;
    
    public class DeptAndEmp {
        private int empId;
        private String empName;
        private String email;
        private String gender;
    
        private Department dept;
    
    
    
        public DeptAndEmp() {
            // 无参构造器必须,创建用于 apache-dbutls 底层调用使用
        }
    
    
        // set/get必须创意用于 apache-dbutls底层反射赋值,取值
        public int getEmpId() {
            return empId;
        }
    
        public void setEmpId(int empId) {
            this.empId = empId;
        }
    
        public String getEmpName() {
            return empName;
        }
    
        public void setEmpName(String empName) {
            this.empName = empName;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public Department getDept() {
            return dept;
        }
    
        public void setDept(Department dept) {
            this.dept = dept;
        }
    
        @Override
        public String toString() {
            return "DeptAndEmp{" +
                    "empId=" + empId +
                    ", empName='" + empName + '\'' +
                    ", email='" + email + '\'' +
                    ", gender='" + gender + '\'' +
                    ", dept=" + dept +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    演示BeanListHandler 存储多表查询中出现的 null空指针

    import com.alibaba.druid.pool.DruidDataSourceFactory;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanListHandler;
    
    import javax.sql.DataSource;
    import java.io.File;
    import java.io.FileInputStream;
    import java.sql.Connection;
    import java.util.List;
    import java.util.Properties;
    
    public class MultiListSelect {
        public static void main(String[] args) {
            try {
                FileInputStream is = new FileInputStream(new File("src/druid.properties"));
                Properties properties = new Properties();
                properties.load(is);
    
                // 创建 druid 数据库连接池
                DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    
                // 获取到数据库当中的连接
                Connection connection = dataSource.getConnection();
    
    
                QueryRunner queryRunner = new QueryRunner();
                // 存储方式: BeanListHandler 将查询的结果集存储到javaBean当中,再将所有的javaBean对象存储到list链表当中
                BeanListHandler<DeptAndEmp> beanListHandler = new BeanListHandler<DeptAndEmp>(DeptAndEmp.class);
    
                // 多表连接查询SQL语句
            String sql = "select dept_id as deptId,dept_name as deptName,employee.emp_id as empId, " +
                         "emp_name as empName,email,gender  " +
                         "from department " +
                         "join employee " +
                         "on employee.emp_id = department.emp_id";
    
                List<DeptAndEmp> deptAndEmpList = queryRunner.query(connection, sql, beanListHandler);
    
                for(DeptAndEmp deptAndEmp : deptAndEmpList) {
                    System.out.println(deptAndEmp);
                }
    
    
            } catch (Exception e) {
                throw new RuntimeException(e);  // 将编译异常转换为运行异常抛出
            }
    
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在这里插入图片描述

    从运行结果上看,我们可以发现,其中 select 语句多表查询的结果集并没有赋值到 Department 类对象当中,其中的属性倒是赋值了。

    我们可以使用 MapListHandle存储形式,解决这个使用BeanListHandler出现空指针异常的现象。

    MapListHandler的使用(具体使用方式查看官方文档https://commons.apache.org/proper/commons-dbutils/apidocs/index.html
    在这里插入图片描述

    key——SQL语句查询的字段
    value——数据库中查询得到的结果

    使用 MapListHandle最终返回 List>,使用 迭代循环foreach 的方式通过查询字段(注意这里的查询字段指的是 数据表结构中的字段名,使用别名是无效的)取出 value,首先根据 Department 类中的 keymap 中取出对应的 value ,并将其封装为 Department 对象中。最后再封装 DeptAndEmp对象到链表当中,这样就解决了 使用 BeanListHandler出现空指针异常的现象。

    具体代码实现如下:

    package Blogs.blogs6;
    
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.MapListHandler;
    
    import javax.sql.DataSource;
    import java.io.File;
    import java.io.FileInputStream;
    import java.sql.Connection;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    
    public class MultiListSelect {
        public static void main(String[] args) {
            try {
                FileInputStream is = new FileInputStream(new File("src/druid.properties"));
                Properties properties = new Properties();
                properties.load(is);
    
                // 创建 druid 数据库连接池
                DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    
                // 获取到数据库当中的连接
                Connection connection = dataSource.getConnection();
    
    
                QueryRunner queryRunner = new QueryRunner();
                // 存储方式: BeanListHandler 将查询的结果集存储到javaBean当中,再将所有的javaBean对象存储到list链表当中
                BeanListHandler<DeptAndEmp> beanListHandler = new BeanListHandler<DeptAndEmp>(DeptAndEmp.class);
    
                // 多表连接查询SQL语句
                String sql = "select dept_id as deptId,dept_name as deptName,employee.emp_id as empId, " +
                        "emp_name as empName,email,gender  " +  // 注意最后的空格,分隔
                        "from department " +
                        "join employee " +
                        "on employee.emp_id = department.emp_id";
    
                // 存储形式为 :  MapListHandler
                MapListHandler mapListHandler = new MapListHandler();
                List<Map<String, Object>> query = queryRunner.query(connection, sql, mapListHandler);  // 执行sql语句
                List<DeptAndEmp> list = new ArrayList<DeptAndEmp>();  // 定义集合链表存储 DeptAndEmp 多对象值
    
                for(Map<String,Object> map : query) {
    
                    Department department = new Department();  // 定义存储对象
                    DeptAndEmp deptAndEmp = new DeptAndEmp();
    
                    // Department: 调用 set方法赋值
                    department.setDeptId((int)map.get("dept_id"));
                    department.setDeptName((String)map.get("dept_name"));
    
                    // DeptAndEmp: 调用 set方法赋值
                    deptAndEmp.setDept(department);
                    deptAndEmp.setEmpId((int)map.get("emp_id"));   // 注意是查询中的字段名,使用别名没有用
                    deptAndEmp.setEmail((String)map.get("email"));
                    deptAndEmp.setEmpName((String) map.get("emp_name"));
                    deptAndEmp.setGender((String) map.get("gender"));
    
                    // 最后封装到链表当中
                    list.add(deptAndEmp);
                }
    
                for(DeptAndEmp deptAndEmp : list) {
                    System.out.println(deptAndEmp);
    
                }
    
            } catch (Exception e) {
                throw new RuntimeException(e);  // 将编译异常转换为运行异常抛出
            }
    
    
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    在这里插入图片描述

    在这里插入图片描述


    2.2 方案二

    创建一个新的 JavaBean,该类包含多表查询的所有字段的属性。 这种方式使用 BeanListHandler 存储形式。没有 null 空指针的存在。

    如下创建的 JavaBean 包含 该SQL 多表查询的中所有的字段值,如下 EmpAndDept 类。

    在这里插入图片描述

    package Blogs.blogs6;
    
    public class EmpAndDept {
        private int deptId;
        private String deptName;
        private int empId;
        private String empName;
        private String email;
        private String gender;
    
        public EmpAndDept() {
            // 无参构造器,必须定义,用于 apache-dbtlis底层的调用
        }
    
        // 同样set/get 也是必须定义的用于 apache-dbtils底层反射赋值,取值
    
    
        public int getDeptId() {
            return deptId;
        }
    
        public void setDeptId(int deptId) {
            this.deptId = deptId;
        }
    
        public String getDeptName() {
            return deptName;
        }
    
        public void setDeptName(String deptName) {
            this.deptName = deptName;
        }
    
        public int getEmpId() {
            return empId;
        }
    
        public void setEmpId(int empId) {
            this.empId = empId;
        }
    
        public String getEmpName() {
            return empName;
        }
    
        public void setEmpName(String empName) {
            this.empName = empName;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        @Override
        public String toString() {
            return "EmpAndDept{" +
                    "deptId=" + deptId +
                    ", deptName='" + deptName + '\'' +
                    ", empId=" + empId +
                    ", empName='" + empName + '\'' +
                    ", email='" + email + '\'' +
                    ", gender='" + gender + '\'' +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    具体代码如下:

    import com.alibaba.druid.pool.DruidDataSourceFactory;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanListHandler;
    import org.apache.commons.dbutils.handlers.MapListHandler;
    
    import javax.sql.DataSource;
    import java.io.File;
    import java.io.FileInputStream;
    import java.sql.Connection;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    
    public class MultiListSelect {
        public static void main(String[] args) {
            try {
                FileInputStream is = new FileInputStream(new File("src/druid.properties"));
                Properties properties = new Properties();
                properties.load(is);
    
                // 创建 druid 数据库连接池
                DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    
                // 获取到数据库当中的连接
                Connection connection = dataSource.getConnection();
    
    
                QueryRunner queryRunner = new QueryRunner();
                // 存储方式: BeanListHandler 将查询的结果集存储到javaBean当中,再将所有的javaBean对象存储到list链表当中
                BeanListHandler<EmpAndDept> beanListHandler = new BeanListHandler<>(EmpAndDept.class);
    
                // 多表连接查询SQL语句
                String sql = "select dept_id as deptId,dept_name as deptName,employee.emp_id as empId, " +
                        "emp_name as empName,email,gender  " +
                        "from department " +
                        "join employee " +
                        "on employee.emp_id = department.emp_id";
    
                List<EmpAndDept> query = queryRunner.query(connection, sql, beanListHandler);
    
                for(EmpAndDept empAndDept : query) {
                    System.out.println(empAndDept);
                }
    
            } catch (Exception e) {
                throw new RuntimeException(e);  // 将编译异常转换为运行异常抛出
            }
            
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    在这里插入图片描述

    在这里插入图片描述


    3. 总结

    1. select 多表查询存储其结果集的数据信息。两种方案:
      1. 第一种方案:创建一个JavaBean 附加上另外一张数据表的 JavaBean 类作为 类属性存在
      2. 该方案不可以使用 BeanListHandler 存储形式,存在 null 空指针异常的问题,而是替换使用 MapListHandle 的方式,通过 循环迭代foreach() 通过 key(注意是数据表结构的字段名,别名没有用),获取到对应的 value 值,再通过 set 方法赋值到对应的类属性中去。从而解决了 使用 BeanListHandler出现空指针异常的现象。
      3. 第二种方案:创建一个新的 JavaBean,该类包含多表查询的所有字段的属性。 这种方式使用 BeanListHandler 存储形式。没有 null 空指针的存在。
    2. 处理多表查询的结果集,这两种方案都可以,各有千秋。
      1. 第一种方案,创建的 JavaBean类少,但是实现起来比较复杂一点,
      2. 第二种方案,创建的 JavaBean 类多,定义的属性多,但是实现起来比较简单。
    3. 具体使用其中的哪一种方案处理都可以,大家可以根据需要自行选择。

    4. 最后

    限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见 !!!

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3j6sAVK-1669713513978)(E:\博客\JDBC博客库\image-20221129084353242.png)]

  • 相关阅读:
    Python3中.whl文件介绍
    7.nginx常用功能模块
    【洛谷 P1029】[NOIP2001 普及组] 最大公约数和最小公倍数问题 题解(更相减损术)
    【无标题】
    如何使用react-router v6快速搭建路由?
    Filter快速入门、Filter执行流程、Filter使用细节、Listener概念、分类、ServletContextListener使用
    函数指针解释
    tomcat多实例部署jenkins
    迷宫生成与路径规划算法-Python3.8-附Github代码
    二叉树汇总
  • 原文地址:https://blog.csdn.net/weixin_61635597/article/details/128101848