MyBatis 学习笔记(二)SQL映射XML文件标签 select、insert、update | XML获取多个参数 | MyBatis实现多表查询 | resultMap标签映射

文章目录

  • 参考资料
  • 一、MyBatis SQL映射文件——输入输出
    • 1.1 SQL映射的XML文件 *Mapper.xml
    • 1.2 mapper 标签
    • 1.3 select 标签
    • 1.4 XML中获取传入的参数
      • 1.4.1 多参案例(一)模糊查询
      • 1.4.2 多参实例(二)parameterType模糊查询
    • 1.5 insert 标签
    • 1.6 update 标签
    • 1.7 delete 标签
    • 1.8 小结
  • 二、MyBatis SQL 映射文件 ——复杂查询
    • 2.1 SQL查询 - 关联表(外键关系)
    • 2.2 对象关联
    • 2.3 resultType 与 resultMap
    • 2.4 一对多查询案例
    • 2.5 多对一映射
    • 2.6 resultMap (多表查询)
    • 2.7 双向关联
    • 2.8 多对多
    • 2.9 小结

参考资料


SPOC

一、MyBatis SQL映射文件——输入输出


学习目标:

  • 掌握通过SQL映射文件进行增删改查
  • 掌握参数的使用
  • 掌握resultMap

1.1 SQL映射的XML文件 *Mapper.xml

SQL 映射 XML文件 的顶级标签(有前后顺序)

标签名 属性 / 描述
mapper 最外层标签,属性 namespace,用于指定Mapper接口类的引用位置,比如com.uni.UserMapper
cache 配置给定命名空间的缓存
cache-ref 从其他命名空间引用缓存配置
resultMap 用来描述数据库结果集和对象的对应关系
sql 可以重用的SQL块,也可以被其他语句引用
insert 映射插入语句
update 映射更新语句
delete 映射删除语句
select 映射查询语句

1.2 mapper 标签

属性:namespace 表示命名空间

  • namespace和子标签(select、insert、update等)的id 联合保证唯一,区别不同的mapper
  • 绑定DAO接口
    • namespace的命名必须跟某个接口同名
    • 接口中的方法与映射文件中SQL语句id一一对应

DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.uni.User"> 
	<select id= "queryAllUser" ...>
    	...
    select>

mapper>

1.3 select 标签

  • select 是MyBatis中最常用的元素之一
  • select 语句有很多属性可以详细配置每一条语句
属性 描述
id 命名空间中唯一的标识符,接口中的方法与映射文件中SQL语句一 一对应
parameterType 传入SQL语句的参数类型
resultType SQL语句返回值类型的完整类名或者别名

1.4 XML中获取传入的参数

查询单个用户通常是需要指定id的,比如在mysql中是这样的:

select * from user where id = 1;

所以在接口中可以这样定义方法:

UserMapper.java

public interface UserMapper{
    User queryUserById(int id);
}

而在XML中如何获取到这个传入的参数呢?

这里可以通过#{} 获取这个参数,若只有一个参数,parameterType 参数可以省略不写,#{}里的内容可任意填,不过只能取一个)

#{}不能用于字符串拼接

UserMapper.xml


<select id="queryUserById" resultType="com.uni.pojo.User">
    select * from smbms_user where id = #{id}
select>

测试:

@Test
public void testQueryUserById(){
    SqlSession sqlSession = MyBatisUtil.getSession();
    User user = sqlSession.getMapper(UserMapper.class).queryUserById(1);
    System.out.println(user);
    sqlSession.close();
}

1.4.1 多参案例(一)模糊查询

现使用 smbms_user表的username用户名和sex性别两个字段来进行模糊查询,使用到的sql语句:

select * from smbms_user where userName like CONCAT('%超%') and sex = '男';

这句话能查询带超字且性别为男的所有用户,现使用MyBatis实现,要点有:

  • parameterType可不写
  • 使用#{param1} 表示第一个参数

原理:

  • 自动封装成Map类型的数据,key: param1 … paramN,或者参数的索引, value: 传入的参数值
  • 自定义名称 @Param注解

方式一:使用param按顺序取参

UserMapper.java

List<User> queryUserLikeNameAndGender(String name, int gender);

UserMapper.xml


<select id="queryUserLikeNameAndGender" resultType="com.uni.pojo.User">
    select * from smbms_user where userName like CONCAT('%', #{param1}, '%') AND gender = #{param2}
select>

方式二:使用@Param注解取参

UserMapper.java

List<User> queryUserLikeNameAndGender(@Param("userName") String name, @Param("gender") int gender);

UserMapper.xml

	<select id="queryUserLikeNameAndGender" resultType="com.uni.pojo.User">
		select * from smbms_user where userName like CONCAT('%', #{userName}, '%') AND gender = #{gender}
	</select>

1.4.2 多参实例(二)parameterType模糊查询

paramterType参数的作用:指定SQL语句传入的参数类型

在XML中,配置了paramterType为实体类后可以使用#{实体类.成员变量}的方式来进行取值

案例:根据用户的名称和性别进行模糊查询

User.java

public class User {
	private Integer id; //id
	private String userName; //用户名称
    private Integer gender;  //性别    
    ...
    //get、set、toString() 略
}

UserMapper.java

List<User> queryUserLikeNameAndGender(User user);

UserMapper.xml

<select id="queryUserLikeNameAndGender" parameterType="com.uni.pojo.User" resultType="com.uni.pojo.User">
    select * from smbms_user where userName like CONCAT('%', #{userName}, '%') AND gender = #{gender}
select>

Test.java

public void testQueryUserLikeNameAndGender(){
    SqlSession sqlSession = MyBatisUtil.getSession();
    User user = new User();
    user.setUserName("孙");
    user.setGender(2);
    List<User> users = sqlSession.getMapper(UserMapper.class).queryUserLikeNameAndGender(user);
    users.forEach(u -> System.out.println(u));
    sqlSession.close();
}

1.5 insert 标签

insert标签是实现sql的insert语句,所以必须指定paramterType属性,但可以没有resultType属性。

比如:

UserMapper.java

void insertUser(User user);

UserMapper.xml

<insert id="insertUser" parameter="com.uni.pojo.User">
	insert into smbms_user(userCode, userName, userPassword) values(#{userCode}, #{userName}, #{userPassword})
insert>

注:insertupdatedelete标签均可以不指定 resultType属性

1.6 update 标签

主要属性:id 、parameterType

案例:修改密码

UserMapper.xml

<update id="modify" parameter="com.uni.pojo.User">
	update smbms_user set userCode = #{userCode}, userName = #{userName}, userPassword=#{userPassword} where id = #{id}
update>

1.7 delete 标签

主要属性:id、parameterType

案例:删除指定id的用户

UserMapper.xml

<delete id = "deleteUserById" parameterType="int">
	delete from smbms_user where id = #{id}
delete>

1.8 小结

  • parameterType

    • 基础数据类型

      • int、String、Date等
      • 只能传入一个,通过#{参数名} 可获取传入的值
    • 复杂数据类型

      • java实体类、Map等
      • 通过#{属性名} 或者 #{map的keyName}即可获取传入值
      • ${} 一般很少用 (不支持占位符的时候使用)
  • resultType

    • 返回基本类型、POJO类型
    • 返回List集合,resultType还是POJO类型
    • 返回Map集合,resultType还是POJO类型(不常用)
    @MapKey("id")
    public Map<Integer, User> findUserByNameReturnMap(@Param("lastName")String lastName);
    
    • 指定返回的Map集合以id为key,也可指定对象别的属性为key

UserMapper.xml

<select id="findUserByNameReturnMap" resultType="myUser">
	select * from user where username like '${lastName}'
select>

二、MyBatis SQL 映射文件 ——复杂查询

2.1 SQL查询 - 关联表(外键关系)

现有 smbms_user 用户表和smbms_role用户角色表

用户表的userRole字段指定为用户角色表的ID

MyBatis 学习笔记(二)SQL映射XML文件标签 select、insert、update | XML获取多个参数 | MyBatis实现多表查询 | resultMap标签映射_第1张图片

现若要显示用户信息包括角色的名称,需要用到多表查询,同样以模糊查询为例,查找姓孙而且是普通员工的SQL语句如下:

SELECT u.userName,r.roleName FROM smbms_user AS u, smbms_role AS r
WHERE u.userName LIKE CONCAT ('%', '孙', '%')
AND u.userRole = 3 AND u.userRole = r.id

此时的结果是:

MyBatis 学习笔记(二)SQL映射XML文件标签 select、insert、update | XML获取多个参数 | MyBatis实现多表查询 | resultMap标签映射_第2张图片

除了User用户本身的信息以外,还多了一个roleName,即角色的名称,所以要想使用MyBatis框架实现多表关联,则需要将Role实体类定义在User实体类中,表示当前用户的角色信息。

2.2 对象关联

对象关联的方式有两种

  • POJO之间引入聚合关系
    • 一对多(1角色,多用户)
    • 一对一(1订单,1用户)
    • 多对一(多用户,1角色)
    • 多对多(订单,产品)
  • 通常在系统设计的时候设定好类之间的关系

2.3 resultType 与 resultMap

  • resultType:直接表示返回类型
    • 基本数据类型
    • 复杂数据类型(没有关联查询时)
  • resultMap:对外部resultMap的引用
    • 应用场景:
      • 数据库字段信息与对象属性不一致
      • 复杂的联合查询,自由控制映射结果

注:resultType 与 resultMap 不能同时存在

2.4 一对多查询案例

以之前的两张表为例,一个角色可对应多个用户。

Role.java

package com.uni.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.sql.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
    private int id;
    private String roleCode;
    private String roleName;
    private int createdBy;
    private Date creationDate;
    private int modifyBy;
    private Date modifyDate;
    private List<User> users;
}

User.java

package com.uni.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
	private Integer id; //id 
	private String userCode; //用户编码
	private String userName; //用户名称
    private Role role; 	// 用户角色
    // ...
}

案例:查询跟当前用户相同角色的所有用户

UserMapper.java

 Role queryAllUserSameRole(User user);     // 查询跟当前用户相同角色的所有用户

UserMapper.xml


<select id="queryAllUserSameRole" parameterType="com.uni.pojo.User" resultMap="oneRole">
    SELECT u.userName,r.roleName FROM smbms_user AS u, smbms_role AS r
    WHERE u.userRole = r.id AND r.id = #{userRole}
select>

<resultMap id="oneRole" type="com.uni.pojo.Role">
    <result property="roleName" column="roleName">result>
    <collection property="users" ofType="com.uni.pojo.User">
        <result property="userName" column="userName">result>
    collection>
resultMap>

TestUserMapper.java

@Test
public void testQueryAllUserNameAndRoleName(){
    SqlSession sqlSession = MyBatisUtil.getSession();
    User user = new User();
    user.setUserRole(3);
    Role role = sqlSession.getMapper(UserMapper.class).queryAllUserSameRole(user);
    for (User u : role.getUsers()) {
        System.out.println(role.getRoleName() + ": " + u.getUserName());
    }
    sqlSession.close();
}

一对多是一个实体类对象里,比如Role角色,含有列表形式的变量用户,表示当前角色的所有用户,此时的结果应当使用来进行处理,将查询结果的字段作为column属性的值,与其对应的则是property属性,这个属性表示实体类里的变量名,比如在这个Demo里就是重新注入了Role角色实体类。

为什么需要用到<colection>标签呢?

因为返回的结果当中,角色名都是相同的,不同的则是用户的信息,所以要用这个标签去给成员变量List user 进行注入

在这个标签里的每个标签是指当前的用户。

2.5 多对一映射

  • resultMap 返回的是一个引用

  • 返回类型还是POJO实体类,上述Demo里是Role类

  • 对象中的各个属性根据查询得到的表数据进行映射

  • id属性需要单独设置 标签(提高性能),其余属性为 标签

    • property 属性指定类中的属性名,column 属性指定查询得到的表中的列名
    • 多对一时,要用 标签单独映射
  • 可根据需求映射属性(不用每个属性都映射,比如上个Demo只映射了角色名称和用户名称)

案例:根据供应商的ID查询相关信息以及旗下所有的订单列表

Provider.java

package com.uni.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Date;
import java.util.List;

@NoArgsConstructor
@AllArgsConstructor
@Data
/* 供应商 */
public class Provider {
    private Integer id;
    private String proName; // 名称
    // ...
}

Bill.java

package com.uni.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Bill {
    private int id;//主键ID
    private String productName;//商品名称
    private Provider provider; // 供应商
	//...
}

ProviderMapper.java

List<Bill> queryProviderById(int id);     // 查询某个供应商的所有订单

ProviderMapper.xml

<select id="queryProviderById" resultMap="oneProvider">
    SELECT p.proName, b.productName FROM smbms_provider p, smbms_bill b
    WHERE p.id = #{id}
select>

<resultMap id="oneProvider" type="Bill">
    <result property="productName" column="productName">result>
    <association property="provider">
        <result property="proName" column="proName">result>
    association>
resultMap>

TestProviderMapper.java

    @Test
    public void queryProviderById(){
        SqlSession sqlSession = MyBatisUtil.getSession();
        List<Bill> bills = sqlSession.getMapper(ProviderMapper.class).queryProviderById(1);
        for (Bill bill : bills)
            System.out.println(bill.getProvider().getProName() + ": " + bill.getProductName());
        sqlSession.close();
    }
}

2.6 resultMap (多表查询)

  • resultMap属性
    • id:resultMap的唯一标识,不可重复
    • type:java实体类
  • resultMap字标签
    • id:一般对应数据库中该行的主键id,设置此项可提高MyBatis的性能
    • result:映射到 JavaBean的某个”简单类型“ 属性
    • association: 映射到 JavaBean的某个“复杂类型”属性,比如 JavaBean类
    • collection: 映射到 JavaBean的某个”复杂类型“ 属性,比如集合

关于 association 标签

  • 用于复杂的类型关联,多对一、一对一(比如一个订单对应一个用户)

  • 内部嵌套: 映射一个嵌套 JavaBean 属性

  • 属性:

    属性值 描述
    property 映射数据库列的实体对象的属性
    javaType 完整 Java 类名或者别名
    resultMap 引用外部 resultMap
  • 子标签

    • id
    • result
      • property:映射数据库列的实体对象的属性
      • column: 数据库列名或者别名

关于 collection 标签

  • 用于复杂类型集合,一对多
  • 内部嵌套:映射一个嵌套结果集到一个列表
  • 属性
属性值 描述
property 映射数据库列的实体对象的属性
ofType 完整 Java类名或者别名(集合所包含的类型)
resultMap 引用外部resultMap
  • 子标签
  • id
  • result
    • property:映射数据库列的实体对象的属性
    • column:数据库列名或者别名

2.7 双向关联

  • 如果对象之间互相都有关联关系,称之为双向关联
  • 目的:任何一方都能关联到另一方
  • 上述例子中的 User用户实体类 和 Role 角色实体类便是双向关联

2.8 多对多

  • 数据库需要三张表关联,比如订单和商品,中间表则是订单详情表

订单 -> 产品

一个订单,多个明细

一个明细,一个产品

2.9 小结

mapper: namespace

select

  • id
  • parameterType
  • resultType / resultMap

insert、updata、delete

  • id
  • parameterType

resultMap

  • id
  • type
  • result
  • association
  • collection

你可能感兴趣的:(#,SSM,mybatis)