Bootstrap

寒假javaEE学习计划---利用MyBatis实现学生信息查询系统

一、项目目标

本项目实现对MyBatis的动态SQL的操作,包括使用动态SQL进行条件查询、更新以及复杂查询操作。本项目要求利用MyBatis的动态SQL的知识完成一个学生信息查询系统。

该系统要求实现2个以下功能:

(1)多条件查询

    1、当用户输入的学生姓名不为空,则只根据学生姓名进行学生信息的查询;

   2、 当用户输入的学生姓名为空,而学生专业不为空,则只根据学生专业进行学生的查询;

   3、 当用户输入的学生姓名和专业都为空,则要求查询出所有学号不为空的学生信息。

(2)单条件查询查询出所有id值小于5的学生的信息

二、实现步骤

功能1、多条件查询

1.项目搭建

创建一个名称为mybatis-demo02的Maven项目

2.数据准备

在名称为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');

实现效果

3.POJO类准备

在项目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 + '\'' +
                '}';
    }
}
4.创建映射文件

在项目src/main/resources目录下创建org.example包,在org.example包下创建映射文件TestStudent.xml,在映射文件中,编写根据学生姓名和专业组合成的条件查询学生信息的动态SQL。TestStudent.xml具体代码如下所示。

<?xml version="1.0" encoding="UTF-8"?>
        	<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        	    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
        	<mapper namespace="org.example.TestStudent">
      <select id="findStudentByNameAndMajor"
                parameterType="student"
                resultType="student">
            select * from dm_student where 1=1
            <choose>
                <when test="name !=null and name !=''">
                    and name like concat('%',#{name}, '%')
                </when>
                <when test="major !=null and major !=''">
    	                and major= #{major}
                </when>
           <otherwise>
                    and sno is not null
               </otherwise>
            </choose>
	    </select>
         </mapper>

在上述代码中,第9~19行代码使用<choose>元素进行SQL拼接,当第一个<when>元素中的条件为真时,只动态组装第一个<when>元素内的SQL片段并执行,否则就继续向下判断第二个<when>元素中的条件是否为真,以此类推,直到某一个<when>元素中的条件为真。当前面所有when元素中的条件都不为真时,则动态组装<otherwise>元素内的SQL片段并执行。

Tip:<choose>(<when>、<otherwise>)相当于Java中的switch...case...default语句,用于多条件判断。

5.修改mybatis-config.xml核心配置文件

在mybatis-config.xml映射文件的<mappers>元素下添加TestStudent.xml映射文件路径的配置,用于将TestStudent.xml映射文件加载到程序中。具体配置代码如下。

<mappers>
    <mapper resource="org.example/TestStudent.xml"/>

    <!--    此处mapper配置的目的是将mapper.xml映射交给mybatis-->
</mappers>
6.编写MyBatisUtils工具类

在项目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实例。
7.编写测试方法
(1)编写测试接口

在org.example包下创建在org.example包下创建持久化类Student的接口文件用于测试

package org.example;

import java.util.List;

/**
 * 接口式开发
 * 根据学生姓名或职业查询学生信息列表
 * 创建接口
 * 1、方法名称保证和映射文件的sql语句的statmentId一致
 * ctrl+shift+t,鼠标悬停接口名,创建接口测试类
 * alt+enter,快速导入类
 */
public interface TestStudent {
        List<Student> findStudentByNameAndMajor(Student student);


}
(2)编写测试方法
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<Student> 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,释放资源。

功能2、单条件查询

1.修改映射文件

在映射文件TestStudent.xml中的<mapper>元素下,编写查询所有id值小于5的学生信息的动态SQL。具体代码如下所示。

 <!--<foreach>遍历List -->
      <select id="findByList" parameterType="java.util.List"
            resultType="student">
        select * from dm_student where id in
        <foreach item="id" index="index" collection="list"
                 open="(" separator="," close=")">
            #{id}
        </foreach>
      </select>

上述配置代码中,使用<foreach>元素迭代List集合,实现学生信息的批量查询操作。其中,<foreach>元素的collection属性用于设置传入的参数为List类型,<foreach>元素将学生id信息存储在List集合中,并对List集合进行遍历,遍历出的值用于构建SQL语句中的in条件语句。

2.编写测试方法

为了验证上述配置,可以在测试类MyBatisTest中,编写测试方法findByListTest(),findByListTest()具体代码如下所示。

(1)编写测试接口
package org.example;

import java.util.List;

/**
 * 接口式开发
 * 根据学生姓名或职业查询学生信息列表
 * 创建接口
 * 1、方法名称保证和映射文件的sql语句的statementId一致
 * ctrl+shift+t,鼠标悬停接口名,创建接口测试类
 * alt+enter,快速导入类
 */
public interface TestStudent {
//       多条件查询
//       List<Student> findStudentByNameAndMajor(Student student);
//        单条件查询
        List<Student>  findByListTest(Student student);

}
  (2)测试方法(关键部分)
  public void testTestFindByListTest() {
        // 获取 SqlSession
        SqlSession session = MyBatisUtils.getSession();
        // 创建 List 集合,封装查询 id
        List<Integer> ids = new ArrayList<>();
        // 将小于5的 id 值放入 list 中
        for (int i = 1; i < 5; i++) {
            ids.add(i);
        }
//        执行查询方法
            List<Student> students = testStudent.findByListTest(ids);

            // 输出查询结果信息
            for (Student student3 : students) {
                System.out.println(student3);
            }

            // 关闭 SqlSession
            session.close();
        }
    }

三、项目效果

功能1、多条件查询

(1)只根据学生姓名进行学生信息的查询

执行测试类MyBatisTest的findStudentByNameOrMajorTest()方法,控制台的输出结果如图3-1所示。

图3-1.findStudentByNameOrMajorTest()方法执行结果(1)

由图3-1中的输出结果分析可知,在查询学生信息时,虽然同时传入了姓名和专业两个查询条件,但MyBatis所生成的SQL只是动态组装了学生姓名条件进行查询。

(2)当用户输入的学生姓名为空,而学生专业不为空,则只根据学生专业进行学生的查询

如果将上述代码中的第10行代码“student.setName("张三");”删除或者注释掉,使SQL只按专业进行查询。再次执行findStudentByNameOrMajorTest ()方法,控制台的输出结果

图3-2.findStudentByNameOrMajorTest()方法执行结果(2)

由图3-2中的输出结果分析可知,MyBatis生成的SQL组装了学生职业进行条件查询,同样查询出了学生信息。

(3)当用户输入的学生姓名和专业都为空,则要求查询出所有学号不为空的学生信息

如果将上述代码中的第10~11行代码都删除或者注释掉(即学生姓名和专业都为空),那么程序的执行结果如图3-3所示。

                                  图3-3.findStudentByNameOrMajorTest()方法执行结果(3)

由图3-3中的输出结果分析可知,当姓名和专业参数都为空时,MyBatis的SQL组装了<otherwise>元素中的SQL片段进行条件查询。

功能2、单条件查询

执行MyBatisTest测试类的findByListTest()方法

四、总结

1.MyBatis动态SQL中的常用元素及其作用。

<if>:判断语句,用于单条件判断。

<choose>(<when>、<otherwise>):相当于Java中的switch...case...default语句,用于多条件判断。

<where>:简化SQL语句中where的条件判断。

<trim>:可以灵活地去除多余的关键字。

<set>:用于SQL语句的动态更新。

<foreach>:循环语句,常用于in语句等列举条件中。

2.在使用<foreach>时,collection属性需要注意的几点:

(1)如果传入的是单参数且参数类型是一个数组或者List的时候,collection属性值分别为array和list(或collection);

(2)如果传入的参数是多个的时候,就需要把它们封装成一个Map了,当然单参数也可以封装成Map集合,这时候collection属性值就为Map的键。

(3)如果传入的参数是POJO包装类的时候,collection属性值就为该包装类中需要进行遍历的数组或集合的属性名。

;