SSM day02

这一章核心的学习内容为SQL的映射文件,即mapper.xml文件的编写方式,需要注意的是,在day01中已经讲解了模糊查询的使用方式,本次就不做过多讲解

查询参数

单个参数

此处单个参数的案例,以day01讲解的模糊查询案例中的concat方式演示

SmbmsUserMapper.xml

因为是单个参数,实际上此处#{myTestName}随便你写啥,如#{xxx},但最好和入参相同,多个的话则要和入参一致

<?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.xshiedu.mapper.SmbmsUserMapper">
    <select id="queryByName" resultType="com.xshiedu.pojo.SmbmsUser">
        select * from smbms_user
        where userName like concat('%',#{xxx},'%')
    </select>
</mapper>

SmbmsUserMapper接口

此处可以使用@param注解,虽然不加也可以,但后期推荐添加,与 #{} 中的变量名一致

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    List<SmbmsUser> queryByName(String userName);
}

测试方法

@Test
public void test04(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.queryByName("张"));
    MybatisUtil.closeSession(session);
}

多个参数

这里的多个参数一般指代2-3个,如果确实太多会采取对象作为入参

SmbmsUserMapper.xml

注意

多个参数推荐使用带有语义内容的,形如#{userName},并且需要在mapper接口添加@param注解定义入参名,否则也会报错

多个参数也可以采用param1、param2或者arg0、arg1的方式作为入参变量名并且不能添加@param注解(这几个变量是mybatis框架默认注册好的)即形如#{param1}、#{param2}或者#{arg0}、#{arg1},但不推荐,因为没有语义

<?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">

<select id="queryByNameAndGender" resultType="com.xshiedu.pojo.SmbmsUser">
    select * from smbms_user
    where userName like concat('%',#{userName},'%')
    and gender = #{gender}
</select>

SmbmsUserMapper接口

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
	List<SmbmsUser> queryByNameAndGender(@Param("userName") String userName,@Param("gender") Integer gender);
}

测试方法

@Test
public void test01(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.queryByNameAndGender("张",1));
    MybatisUtil.closeSession(session);
}

对象作为参数

当参数数量较多时,可以采用对象作为参数的方式,方式也比较简单(实际上,底层源码都是将对象解析成Map对象,再进行拼接查询的)

SmbmsUserMapper.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">

<select id="queryByNameAndGender2" resultType="com.xshiedu.pojo.SmbmsUser">
    select * from smbms_user
    where userName like concat('%',#{userName},'%')
    and gender = #{gender}
</select>

SmbmsUserMapper接口

此处有同学可能会问,是否可以使用方法重载,注意mapper配置文件中要求id唯一,即方法名,因而不能使用方法重载

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
	List<SmbmsUser> queryByNameAndGender2(SmbmsUser user);
}

测试方法

@Test
public void test02(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    SmbmsUser user = new SmbmsUser();
    user.setGender(1);
    user.setUserName("张");
    System.out.println(mapper.queryByNameAndGender2(user));
    MybatisUtil.closeSession(session);
}

多表查询

业务说明

多表查询指的是二表以上的联查,此案例以查询管理员表角色表为案例,假设要查询的为用户名字、用户角色名、用户地址,具体sql语句如下

select a.id,a.userName,b.roleName,address
from smbms_user a,smbms_role b
where a.userRole = b.id

视图对象(VO)

对于这种返回指定列的情况,一般建议新建vo包,创建对应的视图对象

注意:此处故意将id写为userId,是为了让演示resultMap标签,如果直接改为id,可以直接使用resultType而不用resultMap

package com.xshiedu.vo;

/**
 * @author : fanglaoc
 * @version 1.0
 * @ClassName UserDetail
 * @description 用户详细信息对象
 * @date : 2020/8/27 1:25
 */
public class UserDetail {
    private Integer userId;
    private String userName;
    private String roleName;
    private String address;

    @Override
    public String toString() {
        return "UserDetail{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", roleName='" + roleName + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

ResultMap标签

在配置使用resultMap时,只需要注意几点即可,具体参照下图
image-1662343996764

应用场景

SmbmsUserMapper.xml

注意:

result标签指代是的将sql查询到的列映射到实体类中的属性

id标签表示的是查询中对应的表的主键,设置后可提升Mybatis性能,当然也可以设置为result标签,如果设置id标签必须放在result标签前,否则报错;联合主键也可以设置多个id标签

<?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">

<resultMap id="userDetail" type="com.xshiedu.vo.UserDetail">
    <id property="userId" column="id"></id>
    <result property="userName" column="userName"></result>
    <result property="roleName" column="roleName"></result>
    <result property="address" column="address"></result>
</resultMap>

<select id="queryUserDetail" resultMap="userDetail">
    select a.id,a.userName,b.roleName,address
    from smbms_user a,smbms_role b
    where a.userRole = b.id
</select>

SmbmsUserMapper接口

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    List<SmbmsUser> queryUserDetail();
}

测试方法

@Test
public void test03(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.queryUserDetail());
    MybatisUtil.closeSession(session);
}

输出结果

[UserDetail{userId=1, userName='系统管理员', roleName='系统管理员', address='北京市海淀区成府路207号'}, UserDetail{userId=2, userName='李明', roleName='经理', address='北京市东城区前门东大街9号'}, UserDetail{userId=5, userName='韩路彪', roleName='经理', address='北京市朝阳区北辰中心12号'}, UserDetail{userId=6, userName='张华', roleName='普通员工', address='北京市海淀区学院路61号'}, UserDetail{userId=7, userName='王洋', roleName='普通员工', address='北京市海淀区西二旗辉煌国际16层'}, UserDetail{userId=8, userName='赵燕', roleName='普通员工', address='北京市海淀区回龙观小区10号楼'}, UserDetail{userId=10, userName='孙磊', roleName='普通员工', address='北京市朝阳区管庄新月小区12楼'}, UserDetail{userId=11, userName='孙兴', roleName='普通员工', address='北京市朝阳区建国门南大街10号'}, UserDetail{userId=12, userName='张晨', roleName='普通员工', address='朝阳区管庄路口北柏林爱乐三期13号楼'}, UserDetail{userId=13, userName='邓超', roleName='普通员工', address='北京市海淀区北航家属院10号楼'}, UserDetail{userId=14, userName='杨过', roleName='普通员工', address='北京市朝阳区北苑家园茉莉园20号楼'}, UserDetail{userId=15, userName='赵敏', roleName='经理', address='北京市昌平区天通苑3区12号楼'}]

小结

1、resultType一般用于实体类和sql语句列一致的情况,resultMap则用于不一致的情况

2、resultType和resultMap只能二选一,本质上使用的均为Map数据结构

3、想要高度自定义属性与列的映射关系,则使用resultMap

resultMap详解

在上面的案例中,我们使用了resultMap实现了自定义的属性和数据库列的映射,以下详细讲解

属性

id:唯一值,作为resultMap的唯一标识

type:对应映射的java实体类

extends(了解):绑定对应继承的resultMap,绑定的值为对应父类resultMap的唯一标识id,主要用于处理存在继承关系的结果集冗余的resultMap现象

案例补充说明:一个数据库查询可能会返回多个不同的结果集(但总体上还是有一定的联系的),下图的discriminator鉴别器标签,用于处理这一类问题,鉴别器与 Java 语言中的 switch 语句相似

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultMap="carResult"/>
    <case value="2" resultMap="truckResult"/>
    <case value="3" resultMap="vanResult"/>
    <case value="4" resultMap="suvResult"/>
  </discriminator>
</resultMap>

<resultMap id="carResult" type="Car" extends="vehicleResult">
  <result property="doorCount" column="door_count" />
</resultMap>

子元素

id:一般对应数据库的主键字段,添加后可提高mybatis性能,常用属性:property column

result:设置数据库列映射到实体类中的简单属性(单个属性值),常用属性:property column

association:设置数据库列映射到实体类中的复杂属性(实体类类型,1对1),其实用方式和resultMap类似,也是有子元素和属性,单独展开讲解

collection:设置数据库列映射到实体类中的复杂属性(集合类型,1对多,实际上多对多在代码中呈现就是通过2个1对多来实现的),单独展开讲解

association子元素

属性

property :映射到实体类对象的属性

javaType:完整的java名或别名,通常映射到一个 JavaBean

resultMap:引用外部resultMap,填写的内容resultMap唯一标识id(常用于association映射的对象是另一个自定义的map)

子元素

id:一般对应数据库的主键字段,添加后可提高mybatis性能,常用属性:property column

result:设置数据库列映射到实体类中的简单属性(单个属性值),常用属性:property column

案例

sql语句

查询的内容为用户id,用户名,用户地址,角色id,角色名,角色代码,因而使用的是2表联查,为了避免sql语句过长,起了别名

select u.id,u.userName,u.address,r.id roleId ,r.roleName,r.roleCode
from smbms_user u,smbms_role r
where u.userRole = r.id
SmbmsUserMapper.xml
<resultMap id="userDetail2" type="com.xshiedu.vo.UserDetail">
    <id property="id" column="id" />
    <result property="address" column="address"/>
    <result property="userName" column="userName"/>
    <association property="role" javaType="com.xshiedu.pojo.SmbmsRole">
        <id property="id" column="roleId" />
        <result property="roleName" column="roleName"/>
        <result property="roleCode" column="roleCode"/>
    </association>
</resultMap>

<select id="queryUserDetail2" resultMap="userDetail2">
    select u.id,u.userName,u.address,r.id roleId ,r.roleName,r.roleCode
    from smbms_user u,smbms_role r
    where u.userRole = r.id
</select>
SmbmsUserMapper接口
package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    List<SmbmsUser> queryUserDetail2();
}
测试方法
@Test
public void test07(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.queryUserDetail2());
    MybatisUtil.closeSession(session);
}
补充:resultMap的extend属性

接口和测试的代码相同,通过extends属性,需要添加resultMap标签进行匹配,如此处的id = “base” 对应下面的 extends = “base”

<resultMap id="base" type="SmbmsUser">
    <id property="id" column="id" />
    <result property="address" column="address"/>
    <result property="userName" column="userName"/>
</resultMap>

<resultMap id="userDetail2" type="com.xshiedu.vo.UserDetail" extends="base">
    <!--       <id property="id" column="id" />
        <result property="address" column="address"/>
        <result property="userName" column="userName"/>-->
    <association property="role" javaType="com.xshiedu.pojo.SmbmsRole">
        <id property="id" column="roleId" />
        <result property="roleName" column="roleName"/>
        <result property="roleCode" column="roleCode"/>
    </association>
</resultMap>

<select id="queryUserDetail2" resultMap="userDetail2">
    select u.id,u.userName,u.address,r.id roleId ,r.roleName,r.roleCode
    from smbms_user u,smbms_role r
    where u.userRole = r.id
</select>

collection子元素

association子元素实现的是1对1的关系,对于1对多多对多的情况,可以使用collection子元素

案例说明:角色和用户存在1对多的关系,本案例目标是查询出所有角色id为2的用户信息

属性

property :映射到实体类对象的属性

ofType:集合中需要映射的JavaBean类型

resultMap:引用外部resultMap,填写的内容resultMap唯一标识id(常用于association映射的对象是另一个自定义的map)

子元素

id:一般对应数据库的主键字段,添加后可提高mybatis性能,常用属性:property column

result:设置数据库列映射到实体类中的简单属性(单个属性值),常用属性:property column

案例

实体类

此实体类只作为一个案例,封装了一部分属性而已

package com.xshiedu.vo;

import com.xshiedu.pojo.SmbmsUser;

import java.util.List;

/**
 * @author : fanglaoc
 * @version 1.0
 * @ClassName RoleList
 * @description TODO
 */
public class RoleList {
    Integer id;
    String roleName;
    String roleCode;
    List<SmbmsUser> smbmsUserList;

    @Override
    public String toString() {
        return "RoleList{" +
                "id=" + id +
                ", roleName='" + roleName + '\'' +
                ", roleCode='" + roleCode + '\'' +
                ", smbmsUserList=" + smbmsUserList +
                '}';
    }

    public String getRoleCode() {
        return roleCode;
    }

    public void setRoleCode(String roleCode) {
        this.roleCode = roleCode;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public List<SmbmsUser> getSmbmsUserList() {
        return smbmsUserList;
    }

    public void setSmbmsUserList(List<SmbmsUser> smbmsUserList) {
        this.smbmsUserList = smbmsUserList;
    }
}
sql语句

查询的内容为用户id,用户名,角色id,角色名,角色代码,因而使用的是2表联查,为了避免sql语句过长,起了别名

 select u.userName,u.id,r.id roleId,r.roleCode,r.roleName
 from smbms_user u,smbms_role r
 where u.userRole = r.id
 and r.id = 2	
SmbmsRoleMapper.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.xshiedu.mapper.SmbmsRoleMapper">
    <resultMap id="roleList" type="com.xshiedu.vo.RoleList">
        <id property="id" column="roleId"></id>
        <result property="roleCode" column="roleCode"/>
        <result property="roleName" column="roleName"/>
        <collection property="smbmsUserList" ofType="SmbmsUser">
            <id property="id" column="id"></id>
            <result property="userName" column="userName"></result>
        </collection>
    </resultMap>

    <select id="queryRole" resultMap="roleList">
        select u.userName,u.id,r.id roleId,r.roleCode,r.roleName
        from smbms_user u,smbms_role r
        where u.userRole = r.id
        and r.id = #{roleId}
    </select>
</mapper>
SmbmsRoleMapper接口
package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsRole;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsRoleMapper {
    List<SmbmsRole> queryRole(@Param("roleId") int id);
}
测试方法
 @Test
public void test08(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsRoleMapper mapper = session.getMapper(SmbmsRoleMapper.class);
    System.out.println(mapper.queryRole(2));
    MybatisUtil.closeSession(session);
}

增删改

注意:

1、增(insert)、删(delete)、改(delete)等标签均没有resultType属性,再加上入参类型可以自动识别,paramterType属性也可以省略

2、在测试类中记得提交事务,否则会回滚,以后可以不用编写,交给第三方管理

新增

新增标签使用的是insert

sql语句

插入所有列

此案例直接写死,正常应该和插入指定列相同,用#{列名}方式

INSERT INTO smbms.smbms_user
VALUES (null, 'zhaomin', '赵咪me', '0000000', 1, '1987-12-04', '18099897657', '北京市昌平区天通苑3区12号楼', 2, 1, '2015-09-12 12:02:12', null, null);
插入指定列
INSERT INTO smbms.smbms_user (userName, userRole)
VALUES (#{userName},#{userRole});

SmbmsUserMapper.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">
<insert id="insertUser">
    INSERT INTO smbms.smbms_user (userName, userRole)
    VALUES (#{userName},#{userRole});
</insert>

SmbmsUserMapper接口

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    void insertUser(SmbmsUser smbmsUser);
}

测试方法

@Test
public void test04(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    SmbmsUser smbmsUser = new SmbmsUser();
    smbmsUser.setUserName("张三丰");
    smbmsUser.setUserRole(1);
    mapper.insertUser(smbmsUser);
    session.commit();
    MybatisUtil.closeSession(session);
}

修改

修改需要的参数一定有主键,还需要至少一个需要修改的列,此处可以使用**@Param注解方式**,但推荐使用传对象的方式作为入参

SmbmsUserMapper.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">
<update id="updateUser">
    update smbms_user
    set userName = #{userName},
    userRole = #{userRole}
    where id = #{id}
</update>

SmbmsUserMapper接口

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
   void updateUser(SmbmsUser smbmsUser);
}

测试方法

@Test
public void test05(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    SmbmsUser smbmsUser = new SmbmsUser();
    smbmsUser.setUserName("张四风");
    smbmsUser.setUserRole(2);
    smbmsUser.setId(26);
    mapper.updateUser(smbmsUser);
    session.commit();
    MybatisUtil.closeSession(session);
}

删除

删除一般是通过主键进行删除,一般参数只需传入主键,此处主键为id

SmbmsUserMapper.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">
<delete id="deleteUser">
    delete from smbms_user
    where id = #{id}
</delete>

SmbmsUserMapper接口

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    void deleteUser(Integer id);
}

测试方法

@Test
public void test06(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    mapper.deleteUser(25);
    session.commit();
    MybatisUtil.closeSession(session);
}