Apache-DButils以及Druid(德鲁伊) 多表连接查询的解决方案:两种
创始人
2024-02-28 14:26:52

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

在这里插入图片描述


每博一文案

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

文章目录

    • Apache-DButils以及Druid(德鲁伊) 多表连接查询的问题
    • 每博一文案
    • 1. 问题描述
    • 2. 解决方案
      • 2.1 方案一
      • 2.2 方案二
    • 3. 总结
    • 4. 最后


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','男');

在这里插入图片描述

在这里插入图片描述

处理存储如下 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;

在这里插入图片描述


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;}@Overridepublic String toString() {return "Department{" +"deptId=" + deptId +", deptName='" + deptName + '\'' +", empId=" + empId +'}';}
}
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;}@Overridepublic String toString() {return "DeptAndEmp{" +"empId=" + empId +", empName='" + empName + '\'' +", email='" + email + '\'' +", gender='" + gender + '\'' +", dept=" + dept +'}';}
}

演示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 beanListHandler = new BeanListHandler(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 deptAndEmpList = queryRunner.query(connection, sql, beanListHandler);for(DeptAndEmp deptAndEmp : deptAndEmpList) {System.out.println(deptAndEmp);}} catch (Exception e) {throw new RuntimeException(e);  // 将编译异常转换为运行异常抛出}}

在这里插入图片描述

从运行结果上看,我们可以发现,其中 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 beanListHandler = new BeanListHandler(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";// 存储形式为 :  MapListHandlerMapListHandler mapListHandler = new MapListHandler();List> query = queryRunner.query(connection, sql, mapListHandler);  // 执行sql语句List list = new ArrayList();  // 定义集合链表存储 DeptAndEmp 多对象值for(Map 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);  // 将编译异常转换为运行异常抛出}}}

在这里插入图片描述

在这里插入图片描述


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;}@Overridepublic String toString() {return "EmpAndDept{" +"deptId=" + deptId +", deptName='" + deptName + '\'' +", empId=" + empId +", empName='" + empName + '\'' +", email='" + email + '\'' +", gender='" + gender + '\'' +'}';}
}

具体代码如下:

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 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 query = queryRunner.query(connection, sql, beanListHandler);for(EmpAndDept empAndDept : query) {System.out.println(empAndDept);}} catch (Exception e) {throw new RuntimeException(e);  // 将编译异常转换为运行异常抛出}}
}

在这里插入图片描述

在这里插入图片描述


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)]

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...