MyBatis 动态 SQL

简介: MyBatis 动态 SQL

MyBatis通过 OGNL 来进行动态 SQL 的使用的。目前, 动态 SQL 支持以下几种标签:

元素 作用 备注
if 判断语句 单条件分支
choose(when、otherwise) 相当于Java中的if else 多条件分支
trim(where、set) 辅助元素 用于处理SQL拼接问题
foreach 循环语句 批量插入、更新、查询
bind 创建一个变量,并绑定到上下文中 用于兼容不同数据库,防止SQL注入等

创建数据库和表

DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `student_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '编号',
  `name` varchar(20) DEFAULT NULL COMMENT '姓名',
  `phone` varchar(20) DEFAULT NULL COMMENT '电话',
  `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  `sex` tinyint(4) DEFAULT NULL COMMENT '性别',
  `locked` tinyint(4) DEFAULT NULL COMMENT '状态(0:正常,1:锁定)',
  `gmt_created` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '存入数据库的时间',
  `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改的时间',
  `delete` int(11) DEFAULT NULL,
  PRIMARY KEY (`student_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='学生表';

接口函数

/**
 * 根据输入的学生信息进行条件检索
 * 1. 当只输入用户名时, 使用用户名进行模糊检索;
 * 2. 当只输入邮箱时, 使用性别进行完全匹配
 * 3. 当用户名和性别都存在时, 用这两个条件进行查询匹配的用
 * @param student
 * @return
 */
List<Student> selectByStudentSelective(Student student);
/**
 * 更新非空属性
 */
int updateByPrimaryKeySelective(Student record);
/**
 * 非空字段才进行插入
 */
int insertSelective(Student record);
/**
 * - 当 studen_id 有值时, 使用 studen_id 进行查询;
 * - 当 studen_id 没有值时, 使用 name 进行查询;
 * - 否则返回空
 */
Student selectByIdOrName(Student record);
/**
 * 根据输入的学生信息进行条件检索
 * 1. 当只输入用户名时, 使用用户名进行模糊检索;
 * 2. 当只输入邮箱时, 使用性别进行完全匹配
 * 3. 当用户名和性别都存在时, 用这两个条件进行查询匹配的用
 */
List<Student> selectByStudentSelectiveWhereTag(Student student);
/**
 * 获取 id 集合中的用户信息
 * @param ids
 * @return
 */
List<Student> selectByStudentIdList(List<Integer> ids);
/**
 * 批量插入学生
 */
int insertList(List<Student> students);
  • if 标签
<!--在 WHERE 条件中使用 if 标签-->
<select id="selectByStudentSelective" resultMap="BaseResultMap" parameterType="com.homejim.mybatis.entity.Student">
  select
  <include refid="Base_Column_List" />
  from student
  where 1=1
  <if test="name != null and name !=''">
    and name like concat('%', #{name}, '%')
  </if>
  <if test="sex != null">
    and sex=#{sex}
  </if>
</select>
<!--UPDATE 更新列中使用 if 标签-->
<update id="updateByPrimaryKeySelective" parameterType="com.homejim.mybatis.entity.Student">
update student
<set>
  <if test="name != null">
    `name` = #{name,jdbcType=VARCHAR},
  </if>
  <if test="phone != null">
    phone = #{phone,jdbcType=VARCHAR},
  </if>
  <if test="email != null">
    email = #{email,jdbcType=VARCHAR},
  </if>
  <if test="sex != null">
    sex = #{sex,jdbcType=TINYINT},
  </if>
  <if test="locked != null">
    locked = #{locked,jdbcType=TINYINT},
  </if>
  <if test="gmtCreated != null">
    gmt_created = #{gmtCreated,jdbcType=TIMESTAMP},
  </if>
  <if test="gmtModified != null">
    gmt_modified = #{gmtModified,jdbcType=TIMESTAMP},
  </if>
</set>
where student_id = #{studentId,jdbcType=INTEGER}
<!--INSERT 动态插入中使用 if 标签-->
<insert id="insertSelective" parameterType="com.homejim.mybatis.entity.Student">
   insert into student
   <trim prefix="(" suffix=")" suffixOverrides=",">
     <if test="studentId != null">
       student_id,
     </if>
     <if test="name != null">
       `name`,
     </if>
     <if test="phone != null">
       phone,
     </if>
     <if test="email != null">
       email,
     </if>
     <if test="sex != null">
       sex,
     </if>
     <if test="locked != null">
       locked,
     </if>
     <if test="gmtCreated != null">
       gmt_created,
     </if>
     <if test="gmtModified != null">
       gmt_modified,
     </if>
   </trim>
   <trim prefix="values (" suffix=")" suffixOverrides=",">
     <if test="studentId != null">
       #{studentId,jdbcType=INTEGER},
     </if>
     <if test="name != null">
       #{name,jdbcType=VARCHAR},
     </if>
     <if test="phone != null">
       #{phone,jdbcType=VARCHAR},
     </if>
     <if test="email != null">
       #{email,jdbcType=VARCHAR},
     </if>
     <if test="sex != null">
       #{sex,jdbcType=TINYINT},
     </if>
     <if test="locked != null">
       #{locked,jdbcType=TINYINT},
     </if>
     <if test="gmtCreated != null">
       #{gmtCreated,jdbcType=TIMESTAMP},
     </if>
     <if test="gmtModified != null">
       #{gmtModified,jdbcType=TIMESTAMP},
     </if>
   </trim>
 </insert>
  • choose 标签
<select id="selectByIdOrName" resultMap="BaseResultMap" parameterType="com.homejim.mybatis.entity.Student">
    select
    <include refid="Base_Column_List" />
    from student
    where 1=1
    <choose>
      <when test="studentId != null">
        and student_id=#{studentId}
      </when>
      <when test="name != null and name != ''">
        and name=#{name}
      </when>
      <otherwise>
        and 1=2
      </otherwise>
    </choose>
  </select>
  • trim(set、where)
<select id="selectByStudentSelectiveWhereTag" resultMap="BaseResultMap" parameterType="com.homejim.mybatis.entity.Student">
   select
   <include refid="Base_Column_List" />
   from student
  <where>
   <if test="name != null and name !=''">
     and name like concat('%', #{name}, '%')
   </if>
   <if test="sex != null">
     and sex=#{sex}
   </if>
  </where>
 </select>
<!--trim 来表示 where-->
<trim prefix="where" prefixOverrides="AND |OR">
</trim>
<!--trim 来表示 set-->
<trim prefix="SET" suffixOverrides=",">
</trim>
  • prefix: 当 trim 元素包含有内容时, 增加 prefix 所指定的前缀
  • prefixOverrides: 当 trim 元素包含有内容时, 去除 prefixOverrides 指定的 前缀
  • suffix: 当 trim 元素包含有内容时, 增加 suffix 所指定的后缀
  • suffixOverrides:当 trim 元素包含有内容时, 去除 suffixOverrides 指定的后缀
  • foreach 标签
  • collection: 必填, 集合/数组/Map的名称.
  • item: 变量名。即从迭代的对象中取出的每一个值
  • index: 索引的属性名。当迭代的对象为 Map 时, 该值为 Map 中的 Key.
  • open: 循环开头的字符串
  • close: 循环结束的字符串
  • separator: 每次循环的分隔符

多参数请使用 @Param 来指定参数的名称, 如果参数是Map指定为 Map 中的对应的 Key 即可。其实上面的 @Param 最后也是转化为 Map 的。

<!--在 where 中使用 foreach-->
<select id="selectByStudentIdList" resultMap="BaseResultMap">
  select
  <include refid="Base_Column_List" />
  from student
  where student_id in
  <foreach collection="list" item="id" open="(" close=")" separator="," index="i">
    #{id}
  </foreach>
</select>
<!--foreach 实现批量插入-->
<insert id="insertList">
  insert into student(name, phone, email, sex, locked)
  values
  <foreach collection="list" item="student" separator=",">
    (
    #{student.name}, #{student.phone},#{student.email},
    #{student.sex},#{student.locked}
    )
  </foreach>
</insert>
  • bind 标签
    bind 标签是通过 OGNL 表达式去定义一个上下文的变量, 这样方便我们使用。
<if test="name != null and name !=''">
  and name like concat('%', #{name}, '%')
</if>

在 MySQL 中, 该函数支持多参数, 但在 Oracle 中只支持两个参数。那么我们可以使用 bind 来让该 SQL 达到支持两个数据库的作用

<if test="name != null and name !=''">
     <bind name="nameLike" value="'%'+name+'%'"/>
     and name like #{nameLike}
</if>

测试

@Test
public void selectByStudent() {
   SqlSession sqlSession = null;
   sqlSession = sqlSessionFactory.openSession();
   StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
   Student search = new Student();
   search.setName("明");
   System.out.println("只有名字时的查询");
   List<Student> studentsByName = studentMapper.selectByStudentSelective(search);
   for (int i = 0; i < studentsByName.size(); i++) {
       System.out.println(ToStringBuilder.reflectionToString(studentsByName.get(i), ToStringStyle.MULTI_LINE_STYLE));
   }
   search.setName(null);
   search.setSex((byte) 1);
   System.out.println("只有性别时的查询");
   List<Student> studentsBySex = studentMapper.selectByStudentSelective(search);
   for (int i = 0; i < studentsBySex.size(); i++) {
       System.out.println(ToStringBuilder.reflectionToString(studentsBySex.get(i), ToStringStyle.MULTI_LINE_STYLE));
   }
   System.out.println("姓名和性别同时存在的查询");
   search.setName("明");
   List<Student> studentsByNameAndSex = studentMapper.selectByStudentSelective(search);
   for (int i = 0; i < studentsByNameAndSex.size(); i++) {
       System.out.println(ToStringBuilder.reflectionToString(studentsByNameAndSex.get(i), ToStringStyle.MULTI_LINE_STYLE));
   }
   sqlSession.commit();
   sqlSession.close();
}
@Test
public void updateByStudentSelective() {
    SqlSession sqlSession = null;
    sqlSession = sqlSessionFactory.openSession();
    StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
    Student student = new Student();
    student.setStudentId(1);
    student.setName("明明");
    student.setPhone("13838438888");
    System.out.println(studentMapper.updateByPrimaryKeySelective(student));
    sqlSession.commit();
    sqlSession.close();
}
@Test
public void insertByStudentSelective() {
    SqlSession sqlSession = null;
    sqlSession = sqlSessionFactory.openSession();
    StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
    Student student = new Student();
    student.setName("小飞机");
    student.setPhone("13838438899");
    student.setEmail("xiaofeiji@qq.com");
    student.setLocked((byte) 0);
    System.out.println(studentMapper.insertSelective(student));
    sqlSession.commit();
    sqlSession.close();
}
@Test
public void selectByIdOrName() {
    SqlSession sqlSession = null;
    sqlSession = sqlSessionFactory.openSession();
    StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
    Student student = new Student();
    student.setName("小飞机");
    student.setStudentId(1);
    Student studentById = studentMapper.selectByIdOrName(student);
    System.out.println("有 ID 则根据 ID 获取");
    System.out.println(ToStringBuilder.reflectionToString(studentById, ToStringStyle.MULTI_LINE_STYLE));
    student.setStudentId(null);
    Student studentByName = studentMapper.selectByIdOrName(student);
    System.out.println("没有 ID 则根据 name 获取");
    System.out.println(ToStringBuilder.reflectionToString(studentByName, ToStringStyle.MULTI_LINE_STYLE));
    student.setName(null);
    Student studentNull = studentMapper.selectByIdOrName(student);
    System.out.println("没有 ID 和 name, 返回 null");
    Assert.assertNull(studentNull);
    sqlSession.commit();
    sqlSession.close();
}
@Test
public void selectByStudentWhereTag() {
    SqlSession sqlSession = null;
    sqlSession = sqlSessionFactory.openSession();
    StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
    Student search = new Student();
    search.setName("明");
    System.out.println("只有名字时的查询");
    List<Student> studentsByName = studentMapper.selectByStudentSelectiveWhereTag(search);
    for (int i = 0; i < studentsByName.size(); i++) {
        System.out.println(ToStringBuilder.reflectionToString(studentsByName.get(i), ToStringStyle.MULTI_LINE_STYLE));
    }
    search.setSex((byte) 1);
    System.out.println("姓名和性别同时存在的查询");
    List<Student> studentsBySex = studentMapper.selectByStudentSelectiveWhereTag(search);
    for (int i = 0; i < studentsBySex.size(); i++) {
        System.out.println(ToStringBuilder.reflectionToString(studentsBySex.get(i), ToStringStyle.MULTI_LINE_STYLE));
    }
    System.out.println("姓名和性别都不存在时查询");
    search.setName(null);
    search.setSex(null);
    List<Student> studentsByNameAndSex = studentMapper.selectByStudentSelectiveWhereTag(search);
    for (int i = 0; i < studentsByNameAndSex.size(); i++) {
        System.out.println(ToStringBuilder.reflectionToString(studentsByNameAndSex.get(i), ToStringStyle.MULTI_LINE_STYLE));
    }
    sqlSession.commit();
    sqlSession.close();
}
@Test
public void selectByStudentIdList() {
    SqlSession sqlSession = null;
    sqlSession = sqlSessionFactory.openSession();
    StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
    List<Integer> ids = new LinkedList<>();
    ids.add(1);
    ids.add(3);
    List<Student> students = studentMapper.selectByStudentIdList(ids);
    for (int i = 0; i < students.size(); i++) {
        System.out.println(ToStringBuilder.reflectionToString(students.get(i), ToStringStyle.MULTI_LINE_STYLE));
    }
    sqlSession.commit();
    sqlSession.close();
}
@Test
public void insertList() {
    SqlSession sqlSession = null;
    sqlSession = sqlSessionFactory.openSession();
    StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
    List<Student> students = new LinkedList<>();
    Student stu1 = new Student();
    stu1.setName("批量01");
    stu1.setPhone("13888888881");
    stu1.setLocked((byte) 0);
    stu1.setEmail("13888888881@138.com");
    stu1.setSex((byte) 1);
    students.add(stu1);
    Student stu2 = new Student();
    stu2.setName("批量02");
    stu2.setPhone("13888888882");
    stu2.setLocked((byte) 0);
    stu2.setEmail("13888888882@138.com");
    stu2.setSex((byte) 0);
    students.add(stu2);
    System.out.println(studentMapper.insertList(students));
    sqlSession.commit();
    sqlSession.close();
}


相关文章
|
4月前
|
SQL Java 测试技术
3、Mybatis-Plus 自定义sql语句
这篇文章介绍了如何在Mybatis-Plus框架中使用自定义SQL语句进行数据库操作。内容包括文档结构、编写mapper文件、mapper.xml文件的解释说明、在mapper接口中定义方法、在mapper.xml文件中实现接口方法的SQL语句,以及如何在单元测试中测试自定义的SQL语句,并展示了测试结果。
3、Mybatis-Plus 自定义sql语句
|
12天前
|
SQL XML Java
mybatis实现动态sql
MyBatis的动态SQL功能为开发人员提供了强大的工具来应对复杂的查询需求。通过使用 `<if>`、`<choose>`、`<foreach>`等标签,可以根据不同的条件动态生成SQL语句,从而提高代码的灵活性和可维护性。本文详细介绍了动态SQL的基本用法和实际应用示例,希望对您在实际项目中使用MyBatis有所帮助。
44 11
|
1月前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
1月前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
2月前
|
SQL Java 数据库连接
mybatis使用四:dao接口参数与mapper 接口中SQL的对应和对应方式的总结,MyBatis的parameterType传入参数类型
这篇文章是关于MyBatis中DAO接口参数与Mapper接口中SQL的对应关系,以及如何使用parameterType传入参数类型的详细总结。
60 10
|
3月前
|
SQL XML Java
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
文章介绍了MyBatis中动态SQL的用法,包括if、choose、where、set和trim标签,以及foreach标签的详细使用。通过实际代码示例,展示了如何根据条件动态构建查询、更新和批量插入操作的SQL语句。
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
|
4月前
|
SQL Java 数据库连接
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
文章讲述了在使用Mybatis时遇到的资源文件找不到的问题,并提供了通过修改Maven配置来解决资源文件编译到target目录下的方法。
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
|
3月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
71 1
|
4月前
|
SQL Java 数据库连接
Mybatis系列之 动态SQL
文章详细介绍了Mybatis中的动态SQL用法,包括`<if>`、`<choose>`、`<when>`、`<otherwise>`、`<trim>`和`<foreach>`等元素的应用,并通过实际代码示例展示了如何根据不同条件动态生成SQL语句。
|
4月前
|
SQL 关系型数据库 MySQL
解决:Mybatis-plus向数据库插入数据的时候 报You have an error in your SQL syntax
该博客文章讨论了在使用Mybatis-Plus向数据库插入数据时遇到的一个常见问题:SQL语法错误。作者发现错误是由于数据库字段中使用了MySQL的关键字,导致SQL语句执行失败。解决方法是将这些关键字替换为其他字段名称,以避免语法错误。文章通过截图展示了具体的操作步骤。