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 。
例如 Department
和DeptAndEmp
分类封装为 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 +
'}';
}
}
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 +
'}';
}
}
演示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); // 将编译异常转换为运行异常抛出
}
}
从运行结果上看,我们可以发现,其中 select 语句多表查询的结果集并没有赋值到 Department 类对象当中,其中的属性倒是赋值了。
我们可以使用 MapListHandle
存储形式,解决这个使用BeanListHandler出现空指针异常的现象。
MapListHandler的使用(具体使用方式查看官方文档https://commons.apache.org/proper/commons-dbutils/apidocs/index.html
key
——SQL语句查询的字段
value
——数据库中查询得到的结果
使用 MapListHandle
最终返回 List<map<String,Object>>
,使用 迭代循环foreach
的方式通过查询字段(注意这里的查询字段指的是 数据表结构中的字段名,使用别名是无效的)取出 value
,首先根据 Department 类中的 key
从 map
中取出对应的 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); // 将编译异常转换为运行异常抛出
}
}
}
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 + '\'' +
'}';
}
}
具体代码如下:
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); // 将编译异常转换为运行异常抛出
}
}
}
3. 总结
- select 多表查询存储其结果集的数据信息。两种方案:
- 第一种方案:创建一个JavaBean 附加上另外一张数据表的 JavaBean 类作为 类属性存在
- 该方案不可以使用 BeanListHandler 存储形式,存在 null 空指针异常的问题,而是替换使用 MapListHandle 的方式,通过 循环迭代
foreach()
通过 key(注意是数据表结构的字段名,别名没有用),获取到对应的 value 值,再通过 set 方法赋值到对应的类属性中去。从而解决了 使用 BeanListHandler出现空指针异常的现象。 - 第二种方案:创建一个新的 JavaBean,该类包含多表查询的所有字段的属性。 这种方式使用
BeanListHandler
存储形式。没有 null 空指针的存在。
- 处理多表查询的结果集,这两种方案都可以,各有千秋。
- 第一种方案,创建的 JavaBean类少,但是实现起来比较复杂一点,
- 第二种方案,创建的 JavaBean 类多,定义的属性多,但是实现起来比较简单。
- 具体使用其中的哪一种方案处理都可以,大家可以根据需要自行选择。
4. 最后
限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见 !!!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3j6sAVK-1669713513978)(E:\博客\JDBC博客库\image-20221129084353242.png)]