本项目实现对MyBatis的动态SQL的操作,包括使用动态SQL进行条件查询、更新以及复杂查询操作。本项目要求利用MyBatis的动态SQL的知识完成一个学生信息查询系统。
该系统要求实现2个以下功能:
1、当用户输入的学生姓名不为空,则只根据学生姓名进行学生信息的查询;
2、 当用户输入的学生姓名为空,而学生专业不为空,则只根据学生专业进行学生的查询;
3、 当用户输入的学生姓名和专业都为空,则要求查询出所有学号不为空的学生信息。
创建一个名称为mybatis-demo02的Maven项目
在名称为mydb的数据库中,创建一个dm_student表,并插入几条测试数据,具体代码如下所示。
# 使用mydb数据库
USE mybatis;
# 创建一个名称为dm_student的表
CREATE TABLE dm_student(
id int(32) PRIMARY KEY AUTO_INCREMENT,
name varchar(50),
major varchar(50),
sno varchar(16)
);
# 插入7条数据
INSERT INTO dm_student VALUES ('1', '张三', '数学', '10001');
INSERT INTO dm_student VALUES ('2', '李四', '英语', '10002');
INSERT INTO dm_student VALUES ('3', '王五', '计算机', '10003');
INSERT INTO dm_student VALUES ('4', '王刚', '化学', '10004');
INSERT INTO dm_student VALUES ('5', '李华', '物理', '10005');
INSERT INTO dm_student VALUES ('6', '李雷', '中文', '10006');
INSERT INTO dm_student VALUES ('7', '张飞', '英语', '10007');
实现效果
在项目src/main/java目录下创建org.example包,在org.example包下创建持久化类Student,在类中声明id、name、major和sno属性,以及属性对应的getter/setter方法。Student类具体代码如下所示
package org.example;
/**
* 学生信息查询系统学生持久化类POJO类
*/
public class Student {
private Integer id; //主键id
private String name; // 姓名
private String major; // 专业
private String sno; // 学号
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", major='" + major + '\'' +
", sno='" + sno + '\'' +
'}';
}
}
在项目src/main/resources目录下创建org.example包,在org.example包下创建映射文件TestStudent.xml,在映射文件中,编写根据学生姓名和专业组合成的条件查询学生信息的动态SQL。TestStudent.xml具体代码如下所示。
在上述代码中,第9~19行代码使用
Tip:
在mybatis-config.xml映射文件的
在项目src/main/java目录下创建Utils包,在utils包下创建MyBatisUtils工具类,该类用于封装读取配置文件信息的代码
package Utils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.Reader;
import static org.apache.ibatis.io.Resources.getResourceAsReader;
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
static { try {
// 使用MyBatis提供的Resources类加载MyBatis的配置文件
Reader reader = getResourceAsReader("mybatis-config.xml");
// 构建SqlSessionFactory工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) { e.printStackTrace();}}
public static SqlSession getSession() {//获取SqlSession对象的静态方法
return sqlSessionFactory.openSession();}
}
//创建MyBatisUtils工具类,该类用于封装读取配置文件信息的代码。
//第16~17行代码读取mybatis-config.xml文件内容到reader对象中;
//第19~20行代码创建SqlSessionFactory类的实例;
//第26~28行代码是定义了一个getSession()静态方法,
//并在静态方法中通过SqlSessionFactory类的实例创建SqlSession实例。
在org.example包下创建在org.example包下创建持久化类Student的接口文件用于测试
package org.example;
import java.util.List;
/**
* 接口式开发
* 根据学生姓名或职业查询学生信息列表
* 创建接口
* 1、方法名称保证和映射文件的sql语句的statmentId一致
* ctrl+shift+t,鼠标悬停接口名,创建接口测试类
* alt+enter,快速导入类
*/
public interface TestStudent {
List findStudentByNameAndMajor(Student student);
}
package org.example;
import Utils.MyBatisUtils;
import junit.framework.TestCase;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import java.util.List;
public class TestStudentTest extends TestCase {
SqlSession sqlSession=null;
TestStudent testStudent=null;
// 获取接口动态代理对象
@Before
public void setUp() throws Exception {
sqlSession = MyBatisUtils.getSession();
testStudent = sqlSession.getMapper(TestStudent.class);
}
public void testFindStudentByNameOrMajorTest() {
// 通过工具类生成SqlSession对象
SqlSession session = MyBatisUtils.getSession();
// Student,封装需要组合查询的条件
Student student = new Student();
student.setName("张三");
student.setMajor("英语");
List students = testStudent.findStudentByNameAndMajor(student);
// 输出查询结果信息
for (Student student2 : students) {
// 打印输出结果
System.out.println(student2);
}
// 关闭SqlSession
session.close();
}
}
上述代码中,第7行代码通过MyBatisUtils工具类获取SqlSession对象;第9~11行代码创建Student对象,封装需要组合查询的条件;第13~14行代码执行SqlSession的查询方法,返回结果集;第16~19行代码使用foreach循环打印查询结果信息;第21行代码关闭SqlSession,释放资源。
在映射文件TestStudent.xml中的
上述配置代码中,使用
为了验证上述配置,可以在测试类MyBatisTest中,编写测试方法findByListTest(),findByListTest()具体代码如下所示。
package org.example;
import java.util.List;
/**
* 接口式开发
* 根据学生姓名或职业查询学生信息列表
* 创建接口
* 1、方法名称保证和映射文件的sql语句的statementId一致
* ctrl+shift+t,鼠标悬停接口名,创建接口测试类
* alt+enter,快速导入类
*/
public interface TestStudent {
// 多条件查询
// List findStudentByNameAndMajor(Student student);
// 单条件查询
List findByListTest(Student student);
}
public void testTestFindByListTest() {
// 获取 SqlSession
SqlSession session = MyBatisUtils.getSession();
// 创建 List 集合,封装查询 id
List ids = new ArrayList<>();
// 将小于5的 id 值放入 list 中
for (int i = 1; i < 5; i++) {
ids.add(i);
}
// 执行查询方法
List students = testStudent.findByListTest(ids);
// 输出查询结果信息
for (Student student3 : students) {
System.out.println(student3);
}
// 关闭 SqlSession
session.close();
}
}
执行测试类MyBatisTest的findStudentByNameOrMajorTest()方法,控制台的输出结果如图3-1所示。
图3-1.findStudentByNameOrMajorTest()方法执行结果(1)
由图3-1中的输出结果分析可知,在查询学生信息时,虽然同时传入了姓名和专业两个查询条件,但MyBatis所生成的SQL只是动态组装了学生姓名条件进行查询。
如果将上述代码中的第10行代码“student.setName("张三");”删除或者注释掉,使SQL只按专业进行查询。再次执行findStudentByNameOrMajorTest ()方法,控制台的输出结果
图3-2.findStudentByNameOrMajorTest()方法执行结果(2)
由图3-2中的输出结果分析可知,MyBatis生成的SQL组装了学生职业进行条件查询,同样查询出了学生信息。
如果将上述代码中的第10~11行代码都删除或者注释掉(即学生姓名和专业都为空),那么程序的执行结果如图3-3所示。
图3-3.findStudentByNameOrMajorTest()方法执行结果(3)
由图3-3中的输出结果分析可知,当姓名和专业参数都为空时,MyBatis的SQL组装了
执行MyBatisTest测试类的findByListTest()方法
(1)如果传入的是单参数且参数类型是一个数组或者List的时候,collection属性值分别为array和list(或collection);
(2)如果传入的参数是多个的时候,就需要把它们封装成一个Map了,当然单参数也可以封装成Map集合,这时候collection属性值就为Map的键。
(3)如果传入的参数是POJO包装类的时候,collection属性值就为该包装类中需要进行遍历的数组或集合的属性名。