SPOC
学习目标:
SQL 映射 XML文件 的顶级标签(有前后顺序)
标签名 | 属性 / 描述 |
---|---|
mapper | 最外层标签,属性 namespace,用于指定Mapper接口类的引用位置,比如com.uni.UserMapper |
cache | 配置给定命名空间的缓存 |
cache-ref | 从其他命名空间引用缓存配置 |
resultMap | 用来描述数据库结果集和对象的对应关系 |
sql | 可以重用的SQL块,也可以被其他语句引用 |
insert | 映射插入语句 |
update | 映射更新语句 |
delete | 映射删除语句 |
select | 映射查询语句 |
属性:namespace 表示命名空间
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>
属性 | 描述 |
---|---|
id | 命名空间中唯一的标识符,接口中的方法与映射文件中SQL语句一 一对应 |
parameterType | 传入SQL语句的参数类型 |
resultType | SQL语句返回值类型的完整类名或者别名 |
查询单个用户通常是需要指定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();
}
现使用 smbms_user
表的username用户名和sex性别两个字段来进行模糊查询,使用到的sql语句:
select * from smbms_user where userName like CONCAT('%超%') and sex = '男';
这句话能查询带超字且性别为男的所有用户,现使用MyBatis实现,要点有:
原理:
方式一:使用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>
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();
}
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>
注:insert
、update
、delete
标签均可以不指定 resultType
属性
主要属性: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>
主要属性:id、parameterType
案例:删除指定id的用户
UserMapper.xml
<delete id = "deleteUserById" parameterType="int">
delete from smbms_user where id = #{id}
delete>
parameterType
基础数据类型
复杂数据类型
resultType
@MapKey("id")
public Map<Integer, User> findUserByNameReturnMap(@Param("lastName")String lastName);
UserMapper.xml
<select id="findUserByNameReturnMap" resultType="myUser">
select * from user where username like '${lastName}'
select>
现有 smbms_user
用户表和smbms_role
用户角色表
用户表的userRole字段指定为用户角色表的ID
现若要显示用户信息包括角色的名称,需要用到多表查询,同样以模糊查询为例,查找姓孙而且是普通员工的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
此时的结果是:
除了User用户本身的信息以外,还多了一个roleName,即角色的名称,所以要想使用MyBatis框架实现多表关联,则需要将Role实体类定义在User实体类中,表示当前用户的角色信息。
对象关联的方式有两种
注:resultType 与 resultMap 不能同时存在
以之前的两张表为例,一个角色可对应多个用户。
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
进行注入
在这个标签里的每个
标签是指当前的用户。
resultMap
返回的是一个引用
返回类型还是POJO实体类,上述Demo里是Role类
对象中的各个属性根据查询得到的表数据进行映射
id属性需要单独设置
标签(提高性能),其余属性为
标签
标签单独映射可根据需求映射属性(不用每个属性都映射,比如上个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();
}
}
关于 association 标签
用于复杂的类型关联,多对一、一对一(比如一个订单对应一个用户)
内部嵌套: 映射一个嵌套 JavaBean 属性
属性:
属性值 | 描述 |
---|---|
property | 映射数据库列的实体对象的属性 |
javaType | 完整 Java 类名或者别名 |
resultMap | 引用外部 resultMap |
子标签
关于 collection 标签
属性值 | 描述 |
---|---|
property | 映射数据库列的实体对象的属性 |
ofType | 完整 Java类名或者别名(集合所包含的类型) |
resultMap | 引用外部resultMap |
订单 -> 产品
一个订单,多个明细
一个明细,一个产品
mapper: namespace
select
insert、updata、delete
resultMap