详解:Mybatis参数获取和动态SQL以及分页功能

news2024/12/29 10:07:43

详解:Mybatis参数获取和动态SQL以及分页功能

  • 前置准备
    • 项目结构
    • 在pom文件导入依赖
    • 创建properties配置文件
    • 创建Mapper接口
    • 创建Mapper映射文件
    • SqlSession对象
    • 创建对应的表在数据库中
    • 实体类
  • SQL语句中的参数获取
    • 单个参数
    • 两个参数
    • 比较
    • 参数找不到的情况
    • 单个参数(类型为实体类)
    • 多个参数(含实体类)
  • 添加数据时获取自增id值
  • 模糊查询
  • 自定义结果映射集
    • 会使用到的元素
    • 实体类
    • 一对一
    • 一对多
    • 其他方式
  • 动态SQL
    • 概述
    • 动态SQL元素
    • IF标签
      • 格式
      • 代码
    • choose,when,otherwise标签
      • 概述
      • 格式
      • 代码
    • where标签
      • Set标签
      • 格式
      • 代码
    • foreach标签
      • 概述
      • 语法
      • 批量插入
      • 批量删除
  • 分页功能

前置准备

项目结构

在这里插入图片描述

在pom文件导入依赖

 <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectLombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>


        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>4.1.4</version>
        </dependency>
    </dependencies> <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectLombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>


        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>4.1.4</version>
        </dependency>
    </dependencies>

创建properties配置文件

创建配置文件,添加数据库运行所需的配置信息,方便给mybatis配置文件赋值

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/hqyj03?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimeZone=Asia/Shanghai
password=yjg
username=root

创建Mapper接口

public interface CourseMapper和public interface StudentMapper

创建Mapper映射文件

CourseMapper.xml和StudentMapper.xml

SqlSession对象

创建在测试方法之前生成SqlSession对象

@Before
    public void test1() throws Exception{
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        //SqlSessionFactoryBuilder 是 MyBatis 提供的用于构建 SqlSessionFactory 的建造者类。
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //SqlSessionFactory 是一个线程安全的工厂类,用于创建 SqlSession 实例
        SqlSessionFactory build = builder.build(inputStream);
        //SqlSession 是 MyBatis 提供的核心接口之一,它是用于与数据库进行交互的主要对象。
        //简单来说,SqlSession 提供了执行 SQL 操作、提交事务、获取映射器(Mapper)等功能。
       sqlSession = build.openSession(true);
    }

创建对应的表在数据库中

CREATE TABLE `student` (
  `stu_id` int(11) NOT NULL AUTO_INCREMENT,
  `stu_name` varchar(255) DEFAULT NULL,
  `stu_age` varchar(255) DEFAULT NULL,
  `stu_salary` decimal(10,2) DEFAULT NULL,
  `stu_birth` date DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `course_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`stu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
CREATE TABLE `course` (
  `course_id` int(11) NOT NULL AUTO_INCREMENT,
  `course_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`course_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

实体类

import lombok.Data;
import java.util.List;
@Data
public class Course {
    private Integer courseId;
    private String   courseName;
    private List<Student> students;//表示一个课程下有多个学生一对多
}
import lombok.Data;
import org.apache.ibatis.type.Alias;
import java.util.Date;
@Data
//@Alias("Stu")
public class Student {
    private Integer stuId;
    private String  stuName;
    private Integer stuAge;
    private Double  stuSalary;
    private Date  stuBirth;
    private Date createTime;
    private Integer courseId;
}

SQL语句中的参数获取

单个参数

Mapper 接口

//通过id查询学生,传递单个参数
Student queryStudentById(Integer id);

映射文件语句

<!--    拿到方法的形参,单个参数-->
    <select id="queryStudentById" resultType="Student">
          select * from student where stu_id=#{id}
    </select>

测试方法

@Test
    public void test4(){
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Student student = mapper.queryStudentById(2);
        System.out.println(student);
    }

使用#{名称}来接收接口方法中的参数值,使用占位符’?'来设置值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VcBGRTkt-1692499903936)(D:\MoreFile\Hqing\SSM\Note\day2\image-20230809173019421.png)]

两个参数

Mapper 接口

Student queryStudentByNameAndAge(@Param("name") String name,@Param("age") int age);

映射文件语句

使用的是${}取值的方式,name值拼接了两个单引号

<select id="queryStudentByNameAndAge" resultType="student">
      select * from student where stu_name='${name}' and stu_age=${age};
</select>

测试方法

@Test
public void test5(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    Student student = mapper.queryStudentByNameAndAge("kun", 18);
    System.out.println(student);
}

也可以使用${名称}来接收,但是使用该方式是通过字符串拼接方式设值,它是直接插入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xxoSx1PT-1692499903937)(D:\MoreFile\Hqing\SSM\Note\day2\image-20230809173158529.png)]

比较

${} 用于表示直接替换参数的值,而 #{} 则用于进行参数的安全处理和预编译。在映射文件中使用 ${} 会将参数的值直接替换进 SQL 语句中,这样可能存在 SQL 注入的风险。因此,推荐使用 #{} 做为参数占位符。

参数找不到的情况

接口中不设置别名的话

Student queryStudentByNameAndAge(String name,int age);

映射文件语句

<select id="queryStudentByNameAndAge" resultType="student">
      select * from student where stu_name='${name}' and stu_age=${age};
</select>

运行测试方法就会报错

Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'name' not found. Available parameters are [arg1, arg0, param1, param2]

根据错误信息,在查询数据库时出现了参数找不到的错误。错误消息中提到可用的参数是 [arg1, arg0, param1, param2],而没有找到参数 name

原因

在获取方法上的参数时,会将参数值存入到一个map中,key名为arg1或者param1表示第一个参数,以此类推表示第二个,第三个。。。。因此会通过key名来获取参数值,map中没有name这个key。只能通过arg或者param的形式来获取。

语句的配置如下即可,也可以换成param1.。。。,当然也可以给参数设置别名。

<select id="queryStudentByNameAndAge" resultType="student">
      select * from student where stu_name='${arg0}' and stu_age=${arg1};
</select>

单个参数(类型为实体类)

Mapper 接口

 //插入数据,参数为实体类型
 int insertStu(Student stu);

映射文件语句

<insert id="insertStu">
    insert into student values (null,#{stuName},#{stuAge},#{stuSalary},#{stuBirth},now())
</insert>

:MyBatis会自动根据Mapper接口中定义的方法和映射文件中的SQL语句,获取实体类的属性并进行映射。

实体类的属性名称需要与映射文件中SQL语句中的占位符一致才能正确映射。同时,映射文件中的SQL语句也需要与Mapper接口中的方法名称一致,才能正确执行对应的SQL操作。

测试方法

@Test
public void test2(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    Student student=new Student(null,"pp",45,555.55,new Date(),null);
    int i = mapper.insertStu(student);
    System.out.println(i);
}

多个参数(含实体类)

Mapper 接口

//参数多种类型,指定数量查询
List<Student> queryStuByLimit(@Param("stu") Student student,@Param("count") Integer Count);

映射文件语句

<select id="queryStuByLimit" resultType="Student">
    select * from student where stu_age=#{stu.stuAge} limit #{count};
</select>

测试方法

@Test
public void test6(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
   Student s1=new Student();
   s1.setStuAge(18);
    List<Student> list = mapper.queryStuByLimit(s1, 2);
    list.forEach(System.out::println);
}

添加数据时获取自增id值

在添加数据时,由于主键设置为自增的,会自动生成值,所以在插入新的数据时不需要设置id值。插入数据后如何获取到自动生成主键值

mapper

  • useGeneratedKeys:是一个插入语句的属性,用于指定是否使用数据库自动生成的主键。
  • keyProperty:是一个映射对象的属性,用于指定将生成的主键值赋给哪个对象的属性。

Mapper 接口

int insertStu(Student stu);

映射文件语句

<insert id="insertStu" useGeneratedKeys="true" keyProperty="stuId">
    insert into student values (null,#{stuName},#{stuAge},#{stuSalary},#{stuBirth},now())
</insert>

测试方法

@Test
public void test(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    Student ss=new Student();
    System.out.println(ss.getStuId());//null
    ss.setStuName("kun");
    ss.setStuAge(20);
    ss.setStuSalary(4563.2);
    ss.setStuBirth(new Date());
    ss.setCourseId(2);
    Integer sss = mapper.insertStu(ss);
    System.out.println(ss.getStuId());//执行插入过后获取到了数据自增的id值
    System.out.println(sss);
}

模糊查询

模糊查询语法:like %值%。因此在xml中编写sql时会进行字符串拼接。可能有时候会导致拼接不成功。因此建议使用concat函数进行%拼接。

CONCAT 函数

SQL 的 CONCAT 函数用于将两个或多个字符串连接在一起。它接受任意数量的参数,并按照参数的顺序将它们连接在一起。

使用 CONCAT 函数的一般语法如下:

CONCAT(string1, string2, ...)

其中,string1string2表示要连接的字符串,可以是列名、常量值或表达式。

Mapper 接口

//模糊查询
List<Student> queryStuByNameLike(String name);

映射文件语句

<select id="queryStuByNameLike" resultType="student">
    select * from student where stu_name like concat('%',#{name},'%');
</select>

测试方法

@Test
public void test7(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    List<Student> nameLike = mapper.queryStuByNameLike("k");
    nameLike.forEach(System.out::println);
}

自定义结果映射集

为什么要使用自定义结果映射集?

当使用实体类来做为返回值类型的时候,会将数据库字段和实体类中的属性进行一一映射。

一张表对应一个实体类,如果此时进行多表查询,那么查询到的记录是包含多张表的记录,而

将一个实体类做为返回值接收是无法获取到多表查询到的所有值的。因此需要手动定义结果

集,来接收来自数据库中多表查询到的值。

多表查询涉及到以下关系:一对一关系,一对多关系,多对多关系

会使用到的元素

使用 <resultMap> 元素:通过定义 <resultMap> 元素,你可以指定如何映射查询结果到自定义的对象。在 <resultMap> 中,你可以使用 <id><result><association><collection> 等元素来描述对象的属性和关联关系。

  • <id> 元素用于指定主键属性的映射。你可以使用它来指定哪个属性对应数据库表的主键列。

  • <result> 元素用于描述普通属性的映射。通过 <result> 元素,你可以将查询结果中的某一列或表达式的结果映射到自定义对象的一个属性上。

  • <association> 元素用于描述对象之间的一对一关联关系。如果你的自定义对象中包含了其他对象作为属性,你可以使用 <association> 元素来定义该关联关系。

  • <collection> 元素用于描述对象之间的一对多关联关系。如果你的自定义对象中包含了一个集合类型的属性,表示与其他对象之间存在一对多的关系,你可以使用 <collection> 元素来定义该关联关系。

  • column 表示数据库表中的列名。通过在 <result><id> 元素中指定 column 属性,你可以告诉 MyBatis 将查询结果中的某个列映射到对象的相应属性上。例如,假设数据库表中有一个列名为 stu_name,你可以通过 column="stu_name" 将其映射到自定义对象的某个属性上。

  • type 表示 Java 类型或 JDBC 类型。在 <result><id> 元素中,你可以使用 type 属性来指定属性的类型或 JDBC 类型。这对于 MyBatis 在处理类型转换时非常有用。例如,假设你的查询结果中的某列是字符串类型,但你想将其映射到自定义对象的 Integer 类型属性上,你可以通过 type="java.lang.Integer" 来指定属性的类型。

  • property 表示对象中的属性名。在 <result><id> 元素中,你可以使用 property 属性来指定查询结果映射到自定义对象的哪个属性上。例如,假设你的自定义对象有一个属性名为 name,你可以通过 property="name" 来指定将查询结果映射到该属性上。

  • javaType 是用来指定属性的 Java 类型的属性。javaType 属性用于告诉 MyBatis 自定义对象中的某个属性的类型是什么。它通常在 <result><id> 元素中使用。

实体类

两个实体类,一个Student,一个Course,两个的属性都写好,当使用数据库查询给对象属性赋值时,如果没有那么对象的属性是null

@Data
public class Student {
    private Integer stuId;
    private String  stuName;
    private Integer stuAge;
    private Double  stuSalary;
    private Date  stuBirth;
    private Date createTime;
    private Integer courseId;
    private Course course;///表示一个学生只有一门课程,多个就要用LIst
    public Student() {}
    public Student(Integer stuId, String stuName, Integer stuAge) {
        this.stuId = stuId;
        this.stuName = stuName;
        this.stuAge = stuAge;
    }
}
@Data
public class Course {
    private Integer courseId;
    private String   courseName;
    private List<Student> students;//表示一个课程下有多个学生一对多
}

一对一

Mapper 接口

//查询学生以及课程信息
List<Student> queryStuAllInfo();

映射文件语句

第一种:使用级联关系

<resultMap id="stuInfoMap1" type="student">
       <!--设置主键映射-->
        <id column="stu_id" property="stuId"></id>
        <result column="stu_name" property="stuName"></result>
        <result column="stu_age" property="stuAge"></result>
        <result column="stu_salary" property="stuSalary"></result>
        <result column="stu_birth" property="stuBirth"></result>
        <result column="create_time" property="createTime"></result>
        <result column="course_id" property="courseId"></result>
        
         <!--设置course表中信息属性肤射-->
        <result column="course_id" property="course.courseId"></result>
        <result column="course_name" property="course.courseName"></result>
    </resultMap>

这段代码定义了一个名为 stuInfoMap1<resultMap>,用于将查询结果映射到 student 对象及其关联的 Course 对象的属性上。其中包含了主键属性、非主键属性以及关联对象的映射关系。

Student 类中的 setCourse 方法(因为引入了lombok依赖)会被 MyBatis 自动调用,传入一个 Course 对象,该对象包含从数据库查询结果中映射得到的 courseIdcourseName 值。然后,setCourse 方法将这些值设置到 Student 对象的关联属性中

第二种:使用association标签自定义引用数据类型映射关系

<resultMap id="stuInfoMap2" type="Student">
    <id column="stu_id" property="stuId"></id>
    <id column="stu_name" property="stuName"></id>
    <id column="stu_age" property="stuAge"></id>

    <association property="course" javaType="Course">
        <id column="course_id" property="courseId"></id>
        <id column="course_name" property="courseName"></id>
    </association>
</resultMap>

<id> 元素特点<id> 元素用于指定主键属性的映射,但同样也可以用于映射普通属性。实际上,<id> 元素是 <result> 元素的一种特殊形式。

stuInfoMap1 一样也是使用了Student 类中的 setCourse 方法,设置值。

第三种:分步查询,查询到学生的信息后,再根据学生的课程id,查询课程信息

<resultMap id="stuInfoMap3" type="student">
<id column="stu_id" property="stuId"></id>
<result column="stu_name" property="stuName"></result>
<result column="stu_age" property="stuAge"></result>
 <association property="course"
 select="com.yjg.mybatis.mapper.CourseMapper.queryCourseById" column="course_id">
        <id column="course_id" property="courseId"></id>
        <result column="course_name" property="courseName"></result>
    </association>
</resultMap>

分析

<association> 元素的 select 属性用于指定一个查询语句的唯一标识符,该语句将在查询主实体时同时加载关联实体。这个查询语句可以是一个独立的 SQL 语句或者引用其它已定义的 <select> 元素。

使用 <association> 元素设置了 property="course",表示关联属性的名称为 course。通过 select 属性指定了查询关联对象 Course 的 SQL 语句的命名空间和方法,这里是 com.yjg.mybatis.mapper.CourseMapper.queryCourseById。通过 column 属性指定了与 student 对象关联的列名 course_id。MyBatis 可以根据 course_id 的值,去查询并获取对应的课程信息,并将其映射到 Course 对象的属性上。然后赋值给主实体对象 Student 的关联属性 course

映射文件语句

<!--    resultMap:指定自定义映射结果集,可以改成stuInfoMap1,stuInfoMap3-->
<select id="queryStuAllInfo" resultMap="stuInfoMap2">
    SELECT s.*,c.course_name from student s left join course c on s.course_id=c.course_id;
</select>

分析

  • <select> 标签表示这是一个查询语句。
  • id="queryStuAllInfo" 表示这个查询语句的唯一标识符是 “queryStuAllInfo”,可以通过这个标识符在代码中进行调用和引用。
  • resultMap="stuInfoMap2" 表示查询结果将使用名为 “stuInfoMap2” 的 ResultMap 进行映射。ResultMap 是一个 MyBatis 的配置,用于将数据库查询结果映射到 Java 对象上。

测试方法

@Test
public void test9(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    //CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
    List<Student> list = mapper.queryStuAllInfo();
    list.forEach(System.out::println);
    }

StudentMapper 对应的映射文件中采用stuInfoMap3自定义映射结果集时,有一部分内容涉及到了关联属性 course 的查询。是通过调用 CourseMapper 中的方法来查询关联的 Course 对象。所以需要CourseMapper 接口的实例对象。

第四种:通过set方法暴力传入

以下是暴力传入

映射文件语句

StudentMapper.xml中的语句

    <select id="queryStudents" resultType="Student">
              select * from student
    </select>

CourseMapper.xml中的语句

<select id="queryCourseById" resultType="com.yjg.mybatis.pojo.Course">
       select * from course where course_id=#{courseId}
</select>

测试方法

  @Test
    public void test9(){
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
       
        List<Student> list = mapper.queryStudents();
         //这时候Course对象是null   下面是暴力传入Course对象
        for (int i = 0; i < list.size(); i++) {
            //获取课程id
            Integer courseId = list.get(i).getCourseId();
            //使用courseId查询course信息
            Course course = courseMapper.queryCourseById(courseId);
            //将查询到的course设置到每个student对象
            list.get(i).setCourse(course);
        }
        list.forEach(System.out::println);

    }

一对多

查询每门课程下的有哪些学生

Mapper 接口

//查询课程以及课程包含的学生
List<Course> queryCourse();

自定义结果映射集

collection属性介绍

在 MyBatis 中,“collection” 属性通常用于与 ResultMap 关联使用:

  1. collection: “collection” 属性用于指定子对象集合的字段名或属性名。它指定了查找子对象集合的方式,可以是一个字段名称或对象属性的名称。
  2. ofType(可选): “ofType” 属性用于指定子对象集合的类型。它可以是一个具体的 Java 类型,用于表示子对象的类型。如果未指定 “ofType” 属性,则 MyBatis 会根据返回的结果集自动推断集合的类型。
  3. column(可选): “column” 属性用于指定子对象集合在数据库表中的列名。它用于在查询结果集中定位子对象集合的数据。如果未指定 “column” 属性,则 MyBatis 会根据属性名自动寻找对应的列。
  4. select(可选): “select” 属性用于指定查询子对象集合的 SQL 语句或映射语句的 ID。它定义了从数据库查询子对象集合的逻辑。如果未指定 “select” 属性,则 MyBatis 会根据父对象的属性自动生成查询语句。
  5. resultMap(可选): “resultMap” 属性用于指定子对象集合的 ResultMap ID。它定义了如何将查询结果映射到子对象集合中的对象。如果未指定 “resultMap” 属性,则 MyBatis 会自动寻找与子对象集合类型对应的 ResultMap。

第一种:使用collction标签来处理集合映射

     <!--    自定义结果映射集-->
    <resultMap id="courseMap1" type="course">
        <id column="course_id" property="courseId"></id>
        <result column="course_name" property="courseName"></result>
           <!--ofType:指定该集命存储的是什么类型-->
        <collection property="students" ofType="student">
            <!--设置student表信息属性映射-->
            <id column="stu_id" property="stuId"></id>
            <!--设置其他值映射-->
            <result column="stu_name" property="stuName"></result>
            <result column="stu_age" property="stuAge"></result>
            <result column="stu_salary" property="stuSalary"></result>
            <result column="stu_birth" property="stuBirth"></result>
            <result column="create_time" property="createTime"></result>
            <result column="course_id" property="courseId"></result>
        </collection>
    </resultMap>

第二种:使用分步查询

StudentMapper.xml表中语句配置

<select id="queryStudentByCourseId" resultType="com.yjg.mybatis.pojo.Student">
         select * from student where course_id=#{courseId}
</select>

CourseMapper.xml中语句配置

<resultMap id="courseMap2" type="course">
    <id column="course_id" property="courseId"></id>
    <result column="course_name" property="courseName"></result>

    <collection property="students"
                select="com.yjg.mybatis.mapper.StudentMapper.queryStudentByCourseId" column="course_id">
        <!--设置student表信息属性映射-->
        <id column="stu_id" property="stuId"></id>
        <!--设置其他值映射-->
        <result column="stu_name" property="stuName"></result>
        <result column="stu_age" property="stuAge"></result>
        <result column="stu_salary" property="stuSalary"></result>
        <result column="stu_birth" property="stuBirth"></result>
        <result column="create_time" property="createTime"></result>
        <result column="course_id" property="courseId"></result>
    </collection>
</resultMap>

映射文件语句

<select id="queryCourse" resultMap="courseMap2">
    SELECT * from course c INNER JOIN
     student s on c.course_id=s.course_id
</select>

测试方法

@Test
public void test10(){
    CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
    List<Course> list = courseMapper.queryCourse();
    list.forEach(System.out::println);
}

其他方式

当自定义对象具有带参数的构造函数或工厂方法时,MyBatis 允许在 SQL 查询语句中直接使用它们来创建对象。这使得你可以通过 SQL 查询结果将数据映射到自定义对象的属性上。

假设有一个自定义对象 Student,它有一个带参数的构造函数:

public class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 其他属性和方法
    // ...
}

现在,可以在 MyBatis 的查询语句中使用这个构造函数来创建 Student 对象并将查询结果映射到它的属性上。以下是一个示例:

<select id="getStudent" resultType="Student">
    SELECT name, age FROM student WHERE id = #{id}
</select>

在上面的示例中,将查询结果映射到 Student 类型的对象上。MyBatis 会查找 Student 类中的带有相应参数的构造函数,并使用该构造函数创建对象实例。然后,将查询结果中的列值分别赋值给构造函数参数所对应的属性。

同样地,如果自定义对象有一个带参数的工厂方法,你也可以在 SQL 查询语句中使用工厂方法来创建对象。以下是一个示例:

public class Student {
    private String name;
    private int age;

    public static Student create(String name, int age) {
        return new Student(name, age);
    }

    // 其他属性和方法
    // ...
}
<select id="getStudent" resultType="Student">
    SELECT name, age FROM student WHERE id = #{id}
</select>

在上面的示例中,MyBatis 会查找 Student 类中的名为 create 的静态工厂方法,并使用该方法创建对象实例。然后,将查询结果中的列值作为参数传递给工厂方法,并将返回的对象实例作为最终的映射结果。

通过使用带参数的构造函数或工厂方法,可以自定义对象的创建过程,并且能够更灵活地与数据库中的数据进行映射。

动态SQL

概述

动态 SQL 是 MyBatis 的强大特性之一。在 JDBC 或其它类似的框架中,开发人员通常

需要手动拼接SQL 语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。动态 SQL 大

大减少了编写代码的工作量,更体现了 MyBatis 的灵活性、高度可配置性和可维护性。

MyBatis 也可以在注解中配置 SQL,但是由于注解功能受限,且对于复杂的 SQL 语句来说可

读性差,所以使用较少。

动态SQL元素

在这里插入图片描述

IF标签

通过条件查询学生信息时,可以通过学生的用户名进行查询,也可以通过年龄进行查询(where age=?),也可以同时使用名字和年龄进行查询(where name=? and age=?)。按照以上的条件,需要写三个不同的SQL操作。实质上,三个SQL的区别在于条件查询的字段不同,因此可以使用动态SQL来动态生成不同查询条件的SQL语句。

格式

<if test="判断条件">
<!--条件为true时执行SQL语句-->
SQL语句
</if>

代码

Mapper 接口

//根据学生属性查询学生
List<Student> queryStudentByParams(Student student);

映射文件语句

用法

<where>:是 MyBatis 中用于构建动态条件的元素,在这里作为条件容器。
<if test="stuName!=null and stuId!=null">:如果传入的参数 stuName 和 stuId 均不为 null,则生成对应的条件语句,并且使用 AND 连接符拼接条件。
<if test="stuId!=null">:如果传入的参数 stuId 不为 null,则生成对应的条件语句,并且使用 AND 连接符拼接条件。
<if test="stuName!=null">:如果传入的参数 stuName 不为 null,则生成对应的条件语句,并且使用 AND 连接符拼接条件。
<select id="queryStudentByParams" resultType="student">
    select * from student
    <where>
        <if test="stuName!=null and stuId!=null">
            and  stu_name=#{stuName} and stu_id=#{stuId}
        </if>
        <if test="stuId!=null">
            and stu_id=#{stuId}
        </if>
        <if test="stuName!=null">
            and  stu_name=#{stuName}
        </if>
    </where>
</select>

测试方法

   @Test
    public void test11(){
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Student stu=new Student();
        stu.setStuName("kun");
        stu.setStuId(2);
        List<Student> list = mapper.queryStudentByParams(stu);
        list.forEach(System.out::println);
    }

choose,when,otherwise标签

概述

choose 标签按顺序判断其内部 when 标签中的判断条件是否成立,如果有一个成立,则执行相应的 SQL 语句,choose 执行结束;

如果都不成立,执行 otherwise 中的 SQL 语句。这类似于 Java 的switch 语句,choose为switch,when 为case,otherwise则为default。

格式

<choose>
<when test="判断条件1">
SQL语句1
</when >
<when test="判断条件2">
SQL语句2
</when >
<when test="判断条件3">
SQL语句3
</when >
<otherwise>
SQL语句4
</otherwise>
</choose>

代码

Mapper 接口

//根据学生属性查询学生2
List<Student> queryStudentByParams2(Student student);

映射文件语句

<select id="queryStudentByParams2" resultType="student">
    select * from student
   <where>
       <choose>
           <when test="stuId!=null">
               and stu_id=#{stuId}
           </when>

           <when test="stuName!=null   and stuName!=''">
               and stu_name=#{stuName}
           </when>

           <otherwise>
               and stu_age=#{stuAge}
           </otherwise>
       </choose>
   </where>
</select>

测试方法

@Test
public void test12(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    Student stu=new Student();

    stu.setStuName("kun");
    List<Student> list = mapper.queryStudentByParams2(stu);
    list.forEach(System.out::println);
}

如果不设置参数值,打印结果是SQL中执行拼接的是otherwise中的SQL语句

where标签

select * from student where 1=1
    <if test="stuName!=null and stuId!=null">
        and  stu_name=#{stuName} and stu_id=#{stuId}
    </if>
    

如果把1=1这个条件去除后,则会拼接成一个错误格式的SQL,SQL中的语句缺少where关键字,如果不写1=1,就还要考虑and的位置。

所以有,where标签在不用写where 1=1这个条件的情况下,拼接条件查询语句时,自动添加where关键字,保证sql格式正确。

<where> 元素可以用于将多个条件语句组合成一个完整的 WHERE 子句。它提供了一种简化 SQL 编写的方式,并且可以动态地根据条件判断生成有效的 WHERE 子句。

<where> 标签会自动处理条件语句之间的逻辑关系,它会移除开头的 AND 或 OR,以免在没有条件的情况下生成无效的语句。

Set标签

MyBatis 的 <set> 标签是一种用于动态生成更新语句中 SET 子句的元素。

在使用 MyBatis 更新记录时,经常需要根据传入的参数来决定更新哪些字段、更新的值是什么。<set> 标签就提供了这样的功能,可以根据条件动态地生成 SET 子句。

格式

<set>
<if test="条件">
字段=更新值
</if>
<if test="条件">
字段=更新值
</if>
<if test="条件">
字段=更新值
</if>
</set>

代码

Mapper 接口

Integer UpdateStudent(Student student);

映射文件语句

<update id="UpdateStudent">
    update student
    <set>
    <if test="stuName != null">stu_name=#{stuName},</if>
    <if test="stuAge != null">stu_age=#{stuAge},</if>
</set>
where stu_id=#{stuId}
</update>

测试方法

@Test
public void test20(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    Student stu=new Student();

    stu.setStuId(2);
    stu.setStuAge(666);
    stu.setStuName("kun");
    System.out.println(mapper.UpdateStudent(stu));
}

foreach标签

概述

相当于for循环语句,能够在SQL中循环遍历出参数为List或者Set等

集合中的参数值

使用场景:一次性添加/删除多个记录

语法

<foreach item="item" index="index"
collection="list|array|map key" open="("separator="," close=")">
参数值
</foreach>

collection 属性有以下三个取值collection 属性有以下三个取值

  1. list:表示接受一个 List 类型的参数。
  2. array:表示接受一个数组类型的参数。
  3. map key:表示接受一个 Map 类型的参数,并以 Map 的键作为集合元素的属性。

属性说明

item:表示本次迭代获取到的每个元素,若collection为List、

Set或者数组,则表示其中存储的每个元素;若为map,则代表

key-value的value,该参数为必选。

index:表示当前迭代的元素的下标,在map中,则指代的是key

open:表示循环从哪里开始

separator:表示在每次遍历出来的值之间以什么符号作为分隔

符。

close:表示该语以什么结束。

collection:表示迭代集合的名称,或者使用@Param指定的名称

批量插入

Mapper 接口

//批量插入:一次性插入多条数据
Integer insertStudentBatch(@Param("stuList") List<Student> stuList);

映射文件语句

<!--    使用foreach标签批量插入-->
    <insert id="insertStudentBatch">
         insert into student(stu_id,stu_name,stu_age) values
         <foreach collection="stuList"   item="one" separator=",">
             (null ,#{one.stuName},#{one.stuAge})
         </foreach>
    </insert>

测试方法

@Test
public void test13(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    ArrayList<Student> stuList=new ArrayList<>();
    stuList.add(new Student(null, "ee", 66));
    stuList.add(new Student(null, "tt", 99));
    stuList.add(new Student(null, "yy", 88));

    Integer integer = mapper.insertStudentBatch(stuList);
    System.out.println(integer);
}

执行语句
在这里插入图片描述

其他属性值没有输入为什么还可以执行?

如果你在插入语句中没有为某个属性指定具体的属性值,且该属性在数据库表中被定义为可为NULL(nullable),那么默认情况下会将该属性值设置为NULL。

批量删除

Mapper 接口

//批量删除
Integer deleteStudentBatch(@Param("deleteList") List<Integer> deleteList);

映射文件语句

<delete id="deleteStudentBatch">
    delete from student where stu_id in
    <foreach collection="deleteList" item="i" open="(" close=")" separator=",">
        #{i}
    </foreach>
</delete>

测试方法

@Test
public void test14(){
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    ArrayList<Integer> list=new ArrayList<>();
    list.add(16);
    list.add(17);
    list.add(18);

    Integer integer = mapper.deleteStudentBatch(list);
    System.out.println(integer);
}

执行结果

分页功能

分页插件的使用----pageHelper
导入pageHelper依赖

<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.4</version>
</dependency>

在核心配置文件中配置分页插件

<!-- 配置pageHelper分页插件-->
<!-- 插件版本5.0之前使用PageHelper 5.0之后使用PageInterceptor-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
</plugin>
</plugins>

代码

Mapper 接口

List<User>queryUserByPage();

映射文件语句

<select id="queryUserByPage" resultType="user">
select * from user
</select>

测试方法

public void test06(){
PageHelper.startPage(1,2);//表示第一页 每页显示两条数据
List<User> users = mapper.queryUserByPage();
PageInfo<User> pageInfo = new PageInfo<>(users);
System.out.println("当前页码:"+pageInfo.getPageNum());
System.out.println("每页显示条数:"+pageInfo.getPageSize());
System.out.println("当前页实际显示条数:"+pageInfo.getSize());
System.out.println("总记录数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("上一页的页码:"+pageInfo.getPrePage());
System.out.println("下一页的页码:"+pageInfo.getNextPage());
System.out.println("是否为第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否为最后一页:"+pageInfo.isIsLastPage());
System.out.println("是否存在上一
页:"+pageInfo.isHasPreviousPage());
System.out.println("是否存在下一页:"+pageInfo.isHasNextPage());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/902476.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言小练习(一)

&#x1f31e; “人生是用来体验的&#xff0c;不是用来绎示完美的&#xff0c;接受迟钝和平庸&#xff0c;允许出错&#xff0c;允许自己偶尔断电&#xff0c;带着遗憾&#xff0c;拼命绽放&#xff0c;这是与自己达成和解的唯一办法。放下焦虑&#xff0c;和不完美的自己和解…

自动方向识别式 TXB型电平转换芯片

大家好,这里是大话硬件。 在上一篇文章分析了LSF型的电平转换芯片,LSF型电平转换芯片最常见是应用在I2C总线上。I2C为OD型总线,LSF使用时增加电阻。 对于不是OD型总线的电平转换,比如UART,SPI,普通GPIO口信号,这些信号在进行双向电平转换使用什么样的芯片呢? 从上面…

Python写一个创意五子棋游戏

前言 在本教程中&#xff0c;我们将使用Python的Tkinter库和OpenAI的GPT-3模型构建一个简单的对话弹窗软件&#xff0c;用于与老板进行对话。我们将介绍如何创建图形用户界面、集成OpenAI API以生成回复&#xff0c;并提供一些进一步的扩展和优化建议。 &#x1f4dd;个人主页→…

岩土工程安全监测隧道中使用振弦采集仪注意要点?

岩土工程安全监测隧道中使用振弦采集仪注意要点&#xff1f; 岩土工程的安全监测是非常重要的&#xff0c;它可以帮助工程师及时发现可能存在的问题&#xff0c;并及时解决&#xff0c;保障施工进度以及施工质量&#xff0c;保障工程的安全运行。其中&#xff0c;振弦采集仪是…

Liunx系统编程:进程信号的概念及产生方式

目录 一. 进程信号概述 1.1 生活中的信号 1.2 进程信号 1.3 信号的查看 二. 信号发送的本质 三. 信号产生的四种方式 3.1 按键产生信号 3.2 通过系统接口发送信号 3.2.1 kill -- 向指定进程发送信号 3.2.2 raise -- 当自身发送信号 3.2.3 abort -- 向自身发送进程终止…

Docker修改daemon.json添加日志后无法启动的问题

docker实战(一):centos7 yum安装docker docker实战(二):基础命令篇 docker实战(三):docker网络模式(超详细) docker实战(四):docker架构原理 docker实战(五):docker镜像及仓库配置 docker实战(六):docker 网络及数据卷设置 docker实战(七):docker 性质及版本选择 认知升…

视频转云存的痛点

现在运营商体系里面&#xff0c;有大量的视频转云存储的需求&#xff0c;但是视频云存储有一个比较大的痛点&#xff0c;就是成本&#xff01; 成本一&#xff1a;存储成本&#xff1b; 我们以1000路2M视频转云存&#xff0c;存储时间为90天为例&#xff08;B端存储时间有时候…

明星都偏爱的多燕瘦活酵素,不含非法添加事件更健康

不少瘦身人士信奉“运动就能瘦”的准则&#xff0c;每天坚持高强度运动&#xff0c;一段时间后却发现&#xff0c;不仅体重没有下降&#xff0c;甚至整个人看起来都变得更加壮实了&#xff0c;这是为什么&#xff1f; 首先&#xff0c;运动是分为减脂和增肌两种类型的&#xff…

我的创作纪念日 - CSDN创作者4周年,感谢平台,未来可期!

CSDN创作者4周年&#xff0c;感谢平台&#xff0c;未来可期&#xff01; 不知不觉已经加入这个平台4周年了&#xff0c;恍惚昨日之景&#xff0c;有些事情&#xff0c;你不在意&#xff0c;平台却已经写好了程序来给它画上了标记&#xff0c;思想无线&#xff0c;故程序也无边…

Vulnhub靶机系列 Hackadmeic.RTB1

系列&#xff1a;Hackademic&#xff08;此系列共2台&#xff09; 难度&#xff1a;初级 信息收集 主机发现 netdiscover -r 192.168.80.0/24端口扫描 nmap -A -p- 192.168.80.143访问80端口 使用指纹识别插件查看是WordPress 根据首页显示的内容&#xff0c;点击target 点击…

(已解决)PySpark : AttributeError: ‘DataFrame‘ object has no attribute ‘iteritems‘

AttributeError: ‘DataFrame’ object has no attribute ‘iteritems’ 原因在使用SparkSession对象中createDataFrame函数想要将pandas的dataframe转换成spark的dataframe时出现的 因为createDataFrame使用了新版本pandas弃用的iteritems()&#xff0c;所以报错 解决办法&…

webSocket 开发

1 认识webSocket WebSocket_ohana&#xff01;的博客-CSDN博客 一&#xff0c;什么是websocket WebSocket是HTML5下一种新的协议&#xff08;websocket协议本质上是一个基于tcp的协议&#xff09;它实现了浏览器与服务器全双工通信&#xff0c;能更好的节省服务器资源和带宽…

这些Linux基础命令你总得掌握吧

B站|公众号&#xff1a;啥都会一点的研究生 写在前面 很多深度学习/机器学习/数据分析等领域&#xff08;或者说大多数在Python环境下进行操作的领域&#xff09;的初学者入门时是在Windows上进行学习&#xff0c;也得益于如Anaconda等工具把环境管理做的如此友善 但如果想在…

阿里网盘海外使用速度很慢

小虎最近在HK使用阿里云盘&#xff0c;速度突然变得很慢&#xff0c;但是百度的没问题。查了发现是阿里的DNS做的不好&#xff0c;所以换了一个DNS速度就上来了。 解决方案 在这个网站&#xff1a;[原创工具] DNS优选(挑选最合适的DNS服务器,拒绝DNS劫下载DNS推荐工具&#x…

如何取消订阅IEEE membership的email

最近小虎开了一个IEEE Student Member&#xff0c;邮箱都快被IEEE给爆箱了。所以想办法取消订阅其邮件&#xff0c;但是保留其member身份。 方法 在profile界面选择communication preferences and policies, Uncheck所有communications&#xff0c;选择I only want to recei…

Flink内核源码解析--Flink中重要的工作组件和机制

Flink内核源码 1、掌握Flink应用程序抽象2、掌握Flink核心组件整体架构抽象3、掌握Flink Job三种运行模式4、理解Flink RPC网络通信框架Akka详解5、理解TaskManager为例子&#xff0c;分析Flink封装Akka Actor的方法和整个调用流程6、理解Flink高可用服务HighAvailabilityServ…

Spring Cloud Alibaba -微服务架构(二)

1. 微服务架构介绍 微服务架构&#xff0c; 简单的说就是将单体应用进一步拆分&#xff0c;拆分成更小的服务&#xff0c;每个服务都是一个可以独立运行的项目。 1.1 微服务架构的常见问题 一旦采用微服务系统架构&#xff0c;就势必会遇到这样几个问题&#xff1a; 这么多小…

最长回文子序列——力扣516

动态规划 int longestPalindromeSubseq(string s){int n=s.length();vector<vector<int>>

聊聊智慧城市的发展

目录 1.智慧城市应该是什么样子 2.智慧城市的实现方案 3.智慧城市会给人们造成的影响 1.智慧城市应该是什么样子 智慧城市是一种基于信息和通信技术的先进城市管理模式&#xff0c;旨在提高城市的运行效率、居民生活质量和可持续发展。智慧城市整合了各种智能设备、传感器、…

segment anything in high quality

致力于解决细节分割不好的情况&#xff0c;可以理解为sam的精细分割的微调版本&#xff0c;但是对原始的分割能力也没有丢失&#xff0c;有点像目标检测中的小目标检测优化算法。总的来说&#xff0c;在原始的sam上增加了hq-features和hq output token以及mlp&#xff0c;来做h…