1. 动态Sql
1.1 动态Sql-where条件
1.1.1 业务需求
需求:根据对象中不为null的数据,充当where条件 进行查询
例子 :
User user = new User();
user.setId(null).setName(null).setAge(100).setSex("男")
Sql: select * from demo_user where
age = #{age}
and sex = #{sex}
1.1.2 编辑测试类
package com.jt;
import com.jt.mapper.UserMapper;
import com.jt.mapper.UserMapper2;
import com.jt.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
public class TestMybatis2 {
@Autowired
private UserMapper2 userMapper;
/**
* 案例1: 测试动态sql
*/
@Test
public void testDemo1(){
User user = new User();
user.setAge(18).setSex("女"); //动态变化的数据
List<User> userList = userMapper.findUserList(user);
System.out.println(userList);
}
}
1.1.3 编辑UserMapper接口
@Mapper
public interface UserMapper2 {
List<User> findUserList(User user);
}
1.1.4 编辑UserMapper.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="com.jt.mapper.UserMapper2">
<!--
动态Sql: 根据对象中不为null的属性当作where条件
语法:
1.如果判断成立,则动态拼接条件
<if test="id !=null ">条件</if>
2.where标签 去除where后边多余的一个and/or
-->
<select id="findUserList" resultType="User">
select * from demo_user
<where>
<if test="id !=null ">id = #{id}</if>
<if test="name !=null">and name = #{name}</if>
<if test="age !=null ">and age = #{age}</if>
<if test="sex !=null ">and sex = #{sex}</if>
</where>
</select>
</mapper>
1.2 动态Sql-set条件
1.2.1 编辑测试类
//执行动态的更新操作
//根据对象中不为null的元素,充当set条件. where id=xxx
@Test
public void testDemo2(){
User user = new User();
user.setId(231).setName("冬天").setAge(18);
userMapper.updateUser(user);
System.out.println("更新成功!!!");
}
1.2.2 编辑业务接口
void updateUser(User user);
1.2.3 编辑xml映射文件
<!--根据对象中不为null的元素,充当set条件.-->
<update id="updateUser">
update demo_user
<set>
<if test="name !=null">name = #{name},</if>
<if test="age !=null">age = #{age},</if>
<if test="sex !=null">sex = #{sex}</if>
</set>
where id = #{id}
</update>
1.3 动态Sql-choose、when、otherwise
1.3.1 业务需求
说明: 如果不想使用所有的条件可以使用choose 类似于java中的switchh或者if else语句 语法:
如果name有值,则按照name查询,否则按照sex查询数据.
Sql:
1. select * from demo_user where name = #{name}
2. select * from demo_user where sex = #{sex}
1.3.2 编辑测试类
@Test
public void testDemo3(){
User user = new User();
user.setName(null).setAge(null).setSex("女");
List<User> userList = userMapper.findUserByNS(user);
System.out.println(userList);
}
1.3.3 编辑业务接口
List<User> findUserByNS(User user);
1.3.4 编辑Mapper 映射文件
<select id="findUserByNS" resultType="User">
select * from demo_user
<where>
<choose>
<when test="name !=null">
name = #{name}
</when>
<when test="age !=null">
age = #{age}
</when>
<otherwise>
sex = #{sex}
</otherwise>
</choose>
</where>
</select>
1.4 resultMap
1.4.1 需求说明
当表中的字段与POJO中的属性名称不一致时,需要使用resultMap的方式进行映射.
1.4.2 创建表
1.4.3 创建POJO对象
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Dog implements Serializable {
private Integer dogId;
private String dogName;
private Integer age;
}
1.4.4 测试结果
现象说明:
表中的字段名称与对象中的属性名称不一致. 结果:数据不能映射.
1.4.4 关于返回属性的说明
resultType : 只能支持字段名称与属性的名称一致时才能自动映射.
resultMap: 可以支持 任意类型的映射 万能的结构
1.4.5 编辑测试类
@Test
public void testDog(){
List<Dog> dogList = dogMapper.findAll();
System.out.println(dogList);
}
1.4.6 编辑Mapper接口
@Mapper
public interface DogMapper {
List<Dog> findAll();
}
1.4.7 编辑Mapper 映射文件
<?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="com.jt.mapper.DogMapper">
<select id="findAll" resultMap="dogRM">
select * from dog
</select>
<resultMap id="dogRM" type="Dog">
<!--ID:代表主键-->
<id column="dog_id" property="dogId"/>
<!--结果集-->
<result column="dog_name" property="dogName"/>
<!--<result column="age" property="age"/>-->
</resultMap>
</mapper>
1.5 开启驼峰规则映射
说明: 在业务中经常出现该现象. 字段 user_id 属性:userId 属性和字段有驼峰映射规则.但是采用resultType的方式进行映射.则不能正常赋值.
解决方案:
1.resultMap 繁琐.
2.开启驼峰映射规则
mybatis:
#定义别名包
type-aliases-package: com.jt.pojo
#将所有的映射文件全部加载
mapper-locations: classpath:/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
2 Mybatis 关联查询
2.1 常见关联关系
- 一对一 一个员工对应一个部门
- 一对多 一个部门对应多个员工
- 多对多
双向的一对多
1.一个老师对应多个学生
2.一个学生对应多个老师
2.2 创建数据表
说明: 一个员工emp对应一个部门dept
表设计如下:
1.emp表:
2. 部门表dept:
2.3 关联查询Sql
2.3.1 笛卡尔积的方式
特点: 只获取2张表的 交集
SELECT * FROM emp,dept
WHERE emp.dept_id = dept.dept_id
2.3.2 连接查询
分类: 1.左连接 2.内连接 3.右连接
/*左连接 emp表当作主表 */
SELECT * FROM
emp
LEFT JOIN
dept
ON
emp.dept_id = dept.dept_id
2.4 封装关联关系
2.4.1 封装Emp对象
package com.jt.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Emp implements Serializable {
private Integer id;
private String name;
private Integer age;
//关联关系: 一个员工对应一个部门
private Dept dept;
//private Integer deptId;
}
2.4.2 封装Dept对象
package com.jt.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Dept implements Serializable {
private Integer deptId;
private String deptName;
//关联 一个部门下有多个员工
private List<Emp> emps;
}
2.5 一对一封装
2.5.1 编辑测试类
package com.jt;
import com.jt.mapper.DogMapper;
import com.jt.mapper.EmpMapper;
import com.jt.mapper.UserMapper2;
import com.jt.pojo.Dog;
import com.jt.pojo.Emp;
import com.jt.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class TestMybatis3 {
@Autowired
private EmpMapper empMapper;
@Test
public void testOneToOne(){
List<Emp> empList = empMapper.findAll();
System.out.println(empList);
}
}
2.5.2 编辑测试接口
@Mapper
public interface EmpMapper {
List<Emp> findAll();
}
2.5.3 编辑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="com.jt.mapper.EmpMapper">
<!--
规则:
1.如果操作单表 一般使用resultType
2.如果进行关联操作,使用resultMap
3.如果是多表关联操作,则不允许出现重名字段.否则映射失败.
-->
<select id="findAll" resultMap="empRM">
SELECT emp.id,emp.name,emp.age,dept.dept_id,
dept.dept_name
FROM emp,dept
WHERE emp.dept_id = dept.dept_id
</select>
<!--
关于自动映射规则:
1.没有关联映射时: 如果属性和字段同名,则可以省略不写.
2.如果有关联映射: 则需要添加自动映射的开关autoMapping="true"
该注解只对当前对象有效 如果有多个对象,则需要添加多次
-->
<resultMap id="empRM" type="Emp" autoMapping="true">
<!--主键是必填项-->
<id column="id" property="id"/>
<!--
知识点:
1.一对一关联封装 association标签
2.必须指定属性的类型 javaType属性
3.autoMapping="true" 自动映射
-->
<association property="dept" javaType="Dept" autoMapping="true">
<!--主键必填项-->
<id column="dept_id" property="deptId"/>
<!--由于一起开启驼峰规则映射.所以下列的操作可以省略-->
<!--<result column="dept_name" property="deptName"/>-->
</association>
</resultMap>
</mapper>
2.5 一对多封装
2.5.1 关联说明
一个部门下,对应多个员工, 主对象是Dept
2.5.2 编辑测试类
//完成一对多封装 一个部门中要求获取多个员工
@Test
public void testMore(){
List<Dept> list = deptMapper.findAll();
System.out.println(list);
}
2.5.4 编辑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="com.jt.mapper.DeptMapper">
<select id="findAll" resultMap="deptRM">
SELECT dept.dept_name,emp.*
FROM dept,emp
WHERE emp.dept_id = dept.dept_id
</select>
<resultMap id="deptRM" type="Dept" autoMapping="true">
<!--主键必须标识-->
<id column="dept_id" property="deptId"/>
<!-- 一对多封装 固定搭配 ofType="" -->
<collection property="emps" ofType="Emp" autoMapping="true">
<id column="id" property="id"></id>
</collection>
</resultMap>
</mapper>
总结:
思想: 面向对象方式!!!
1.动态Sql: 不清楚用户到底传递了什么数据!!!
1.动态查询 2.动态更新 3.分支结构关联关系
一对一/一对多/多对多(双向一对多)resultMap 万能的数据封装的结构体系
一对一: association property=“dept” javaType=“Dept”
一对多: collection property=“emps” ofType=“Emp”