Mybatis——动态SQL

这篇博客详细介绍了Mybatis中的动态SQL操作,包括多对一和一对多的处理方式,如按照查询和结果的嵌套处理。还探讨了动态SQL的概念,列举了if、choose、trim和foreach等元素的用法,并给出了环境搭建和实例测试的过程。同时强调了SQL可读性、属性对应以及日志在排查错误中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、多对一处理

  • 多个学生,对应一个老师
  • 对于学生这边而言,关联,多个学生关联一个老师【多对一】
  • 对于老师而言,集合,一个老师,有很多学生【一对多】

SQL:

CREATE TABLE teacher(
	id INT(10) NOT NULL,
	name VARCHAR(30) DEFAULT NULL,
	PRIMARY KEY (id)
)ENGINE=INNODB;

INSERT INTO teacher (id, name) VALUES (1, '果冻奶酪');

CREATE TABLE student(
	id INT(10) NOT NULL,
	name VARCHAR(30) DEFAULT NULL,
	tid INT(10) DEFAULT NULL,
	PRIMARY KEY(id),
	KEY fktid (tid),
	CONSTRAINT fktid FOREIGN KEY (tid) REFERENCES teacher (id)
)ENGINE=INNODB;

INSERT INTO student (id, name, tid) VALUES (1, '小明', 1);
INSERT INTO student (id, name, tid) VALUES (2, '小红', 1);
INSERT INTO student (id, name, tid) VALUES (3, '小张', 1);
INSERT INTO student (id, name, tid) VALUES (4, '小李', 1);
INSERT INTO student (id, name, tid) VALUES (5, '小王', 1);

测试环境搭建——这里运营了lombok

1、导入lombok

<dependencies>
	<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<version>1.18.10</version>
	</dependency>
</dependencies>

2、新建实体类Teacher、Student 

@Data
public class Teacher {
    private int id;
    private String name;
}
@Data
public class Student {
    private int id;
    private String name;

    //学生需要关联一个老师
    private Teacher teacher;
}

 3、建立Mapper接口

public interface TeacherMapper {

    @Select("select * from teacher where id = #{id}")
    Teacher getTeacher(@Param("id") int id);

}
public interface StudentMapper {
}

 4、建立Mapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 绑定Mapper接口 -->
<mapper namespace="com.oykq.dao.StudentMapper">

</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 绑定Mapper接口 -->
<mapper namespace="com.oykq.dao.TeacherMapper">

</mapper>

5、核心配置文件中绑定注册Mapper接口或者文件

<mappers>
	<mapper class="com.oykq.dao.TeacherMapper"/>
	<mapper class="com.oykq.dao.StudentMapper"/>
</mappers>

 6、测试查询是否成功

@Test
public void test(){
	SqlSession sqlSession = MybatisUtils.getSqlSession();
	TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
	Teacher teacher = mapper.getTeacher(1);
	System.out.println(teacher);
	sqlSession.close();
}

按照查询嵌套处理

<!--
思路;
	1.查询所有的学生信息
	2.根据查询出来的学生的tid,寻找对应的老师     子查询
-->

<select id="getStudent" resultMap="StudentTeacher">
	select * from student;
</select>
    
<resultMap id="StudentTeacher" type="Student">
	<result property="id" column="id"/>
	<result property="name" column="name"/>
	<!-- 复杂的属性,需要单独处理
		对象:association
		集合:collection
	-->
	<!--
		javaType:把SQL语句查询出来的结果集,封装给某个类的对象(可省略)
		select:下一条要执行的SQL语句
		property:注入给实体类的某个属性
		上一次的查询结果集中,用哪些值作为条件去执行下一条SQL语句
	-->
	<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

<select id="getTeacher" resultType="Teacher">
	select * from teacher where id = #{id};
</select>

按照结果嵌套处理

<!-- 按照结果嵌套查询 -->
<select id="getStudent2" resultMap="StudentTeacher2">
	select s.id sid, s.name sname, t.name tname
	from student s, teacher t
	where s.tid = t.id
</select>
    
<resultMap id="StudentTeacher2" type="Student">
	<result property="id" column="sid"/>
	<result property="name" column="sname"/>
	<association property="teacher" javaType="Teacher">
		<result property="name" column="tname"/>
	</association>
</resultMap>

MySQL多对一查询方式:

  • 子查询
  • 联表查询

二、一对多处理

比如一个老师有多个学生

对于老师而言,就是一对多的关系

环境搭建

1、环境搭建
实体类

@Data
public class Student {
    private int id;
    private String name;
    private int tid;

}
@Data
public class Teacher {
    private int id;
    private String name;

    //一个老师拥有多个学生
    private List<Student> students;

}

按照结果嵌套处理

<!-- 按照结果嵌套查询 -->
<select id="getTeacher" resultMap="TeacherStudent">
	select s.id sid, s.name sname, t.name tname,t.id tid
	from teacher t, student s
	where t.id = s.tid and t.id = #{tid};
</select>

<resultMap id="TeacherStudent" type="Teacher">
	<result property="id" column="tid"/>
	<result property="name" column="tname"/>
	<!-- 复杂的属性,需要单独处理  对象:association  集合:collection
		javaType=""  指定类型的属性
		集合中的泛型信息,我们使用ofType获取
	-->
	<collection property="students" ofType="Student">
		<result property="id" column="sid"/>
		<result property="name" column="sname"/>
		<result property="tid" column="tid"/>
	</collection>
</resultMap>

按照查询嵌套处理

<select id="getTeacher2" resultMap="TeacherStudent2">
	select * from mybatis.teacher where id = #{tid};
</select>

<resultMap id="TeacherStudent2" type="Teacher">
	<result property="id" column="id"/>
	<result property="name" column="name"/>
	<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherID" column="id"/>
</resultMap>
    
<select id="getStudentByTeacherID" resultType="Student">
	select * from mybatis.student where tid = #{tid};
</select>

小结

1、关联 - association【多对一】
2、集合 - collection【一对多】
3、javaType & ofType

  1. javaType用来指定实体类中属性的类型
  2. ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束条件

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段的对应问题
  • 如果问题不好排查错误,可以使用日志,建议用Log4j

慢SQL:

面试必问:

  • Mysql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

三、动态SQL

什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句

利用动态 SQL,可以彻底摆脱这种痛苦。

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

搭建环境 

CREATE TABLE blog(
	id varchar(50) NOT NULL COMMENT '博客id',
	title varchar(100) NOT NULL COMMENT '博客标题',
	author varchar(30) NOT NULL COMMENT '博客作者',
	create_time datetime NOT NULL COMMENT '创建时间',
	views int(30) NOT NULL COMMENT '浏览量'
)ENGINE=InnoDB;

 创建一个基础工程

  1. 导包
  2. 编写配置文件
  3. 编写实体类
  4. 编写对应实体类的Mapper接口
  5. 编写对应Mapper.xml文件
  6. 测试

IF

<select id="queryBlogIF" parameterType="map" resultType="Blog">
	select * from mybatis.blog where 1 = 1
	<if test="title != null">
		and title = #{title}
	</if>
	<if test="author != null">
		and author = #{author}
	</if>
</select>

choose (when, otherwise)

<select id="queryBlogChoose" parameterType="map" resultType="blog">
	select * from mybatis.blog
	<where>
		<choose>
			<when test="title != null">
				title = #{title}
			</when>
			<when test="author != null">
				and author = #{author}
			</when>
			<otherwise>
				and views = #{views}
			</otherwise>
		</choose>
	</where>
</select>
<update id="updateBlog" parameterType="map">
	update mybatis.blog
	<set>
		<if test="title != null">
			title = #{title},
		</if>
		<if test="author != null">
			author = #{author}
		</if>
	</set>
	where id = #{id}
</update>

所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
if
where , choose , set , when

SQL片段

有时候,我们可能会将一些公共的部分抽取出来,方便复用

1、用sql标签抽取公共的部分

<sql id="if_title_author">
	<if test="title != null">
		title = #{title}
	</if>
	<if test="author != null">
		and author = #{author}
	</if>
</sql>

2、在需要的地方用include标签引用

<select id="queryBlogIF" parameterType="map" resultType="blog">
	select * from mybatis.blog
	<where>
		<include refid="if_title_author"></include>
	</where>
</select>

注意事项:

  • 最好基于单表定义SQL片段
  • 不要存在where标签

Foreach

select * from user where 1=1 and
	<foreach item="id" collection="ids"
      open="(" separator="or" close=")">
        #{id}
  	</foreach>
 (id = 1 or id = 2 or id = 3)

  

<!--
	select * from blog where 1=1 and (id=1 or id=2 or id=3)

	我们传递一个Map,在Map中可以存在一个集合
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
	select * from mybatis.blog
	<where>
		<foreach item="id" collection="ids" open="(" separator="or" close=")">
			id = #{id}
		</foreach>
	</where>
</select>

动态SQL就是拼接SQL语句,我们只要保证SQL语句的正确性,按照SQL的格式,去排列组合就可以了

建议:

  • 先在Mysql中写出完整的SQL语句,再对应地去修改成为动态SQL实现通用


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值