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时,只需要注意几点即可,具体参照下图
应用场景
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);
}