mybatis
简介
mybatis是一款优秀的持久层框架,属于ORM映射。前身是ibatis。
mybatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作SqlSess。mybatis通过开发者书写SQL语句,以及对象模型和关系模型的映射,完成对象模型和关系模型的数据转换。同时支持延迟加载,缓存,映射等。
mybatis可以通过简单的XML或注解来配置和映射对象模型和关系模型,从而完成对象数据和关系数据的转换。
MyBatis中文网:https://mybatis.net.cn/
mybatis的核心对象:SqlSessionFactory SqlSession(相当于一个连接)
mybatis的配置文件有两种:
Mybatis.cfg.xml:主配置文件,用于配置数据源,链接各种ORM映射文件,以及实体类、别名、日志等
多个ORM映射文件:用于书写实体类和表的映射关系,操作数据库的SQL语句,以及配置持久接口
环境搭建
1、导入maven依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
2、建立数据库表
CREATE TABLE t_student(
pk_studentId INT PRIMARY KEY auto_increment,
s_name VARCHAR(20),
s_birthday date,
s_phone VARCHAR(50)
);
3、建立实体类
public class StudentBean {
//编号
private Integer id;
//姓名
private String name;
//生日
private LocalDate birthday;
//电话
private String phone;
}
4、建立业务接口
public interface IStudentService {
public void add(StudentBean studentBean);
public void del(Integer id);
public void update(Integer id,String phone);
public List<StudentBean> findAll();
public StudentBean findById(Integer id);
}
5、建立mapper接口
public interface IStudentMapper {
public void add(StudentBean studentBean);
public void del(Integer id);
public void update(Integer id,String phone);
public List<StudentBean> findAll();
public StudentBean findById(Integer id);
}
6、将mybatis.cfg.xml拷入resources目录中,在编译后,该文件会放在class文件目录的根目录中。
7、在resources目录中,新建文件夹:com/project/mapper,该文件夹的目录和mapper接口所在包同名。然后,将mapper文件放入该目录。
8、编辑mybatis.cfg.xml
<settings><!--配置日志-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<typeAliases><!--配置实体类的别名,当配置package时,表示指定包中的所有类型允许用类名作为别名-->
<package name="com.project.bean"/>
</typeAliases>
<!--配置驱动类-->
<transactionManager type="JDBC"></transactionManager>
<!--配置连接数据库的URL路径,allowMultiQueries=true表示允许在一个语句块中书写多条SQL语句-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true"/>
<!--mysql登录用户名-->
<property name="username" value="root"/>
<!--mysql登录密码-->
<property name="password" value="yks957"/>
</dataSource>
<mappers><!--扫描指定包中所有的mapper文件-->
<package name="com.project.mapper"/>
</mappers>
9、将mapper文件的文件名,改为mapper接口名IStudentMapper.xml。表示该文件为指定接口中的方法提供执行SQL语句。
10、编辑IStudentMapper.xml
将命名空间,定义为mapper接口全路径
<mapper namespace="com.project.mapper.IStudentMapper">
<!--id必须和接口方法同名,表示给哪个方法提供执行的SQL语句-->
<insert id="add">
insert into t_student(s_name,s_birthday,s_phone)
values (#{name},#{birthday},#{phone});
</insert>
</mapper>
#{name}表示占位符。如果参数为实体对象,#{name}表示将实体对象指定的属性值填充该占位符。
11、创建service业务主键父类
public class BaseService {
// 得到会话工厂,用于存放解析了配置文件所有的信息
private static SqlSessionFactory factory;
static {
try {
//读取class文件根目录中的mybatis主配置文件
Reader r = Resources.getResourceAsReader("mybatis.cfg.xml");
//创建会话工厂
factory = new SqlSessionFactoryBuilder().build(r);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 得到会话对象,一个会话相当于一个链接
*
* @return 会话对象
*/
public SqlSession getSession() {
return factory.openSession();
}
}
12、创建业务接口实现类
public void add(StudentBean studentBean) {
//得到会话
SqlSession session = this.getSession();
//得到mapper接口的实现类对象
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
//执行添加操作
mapper.add(studentBean);
//提交事务
session.commit();
//关闭session
session.close();
}
删除
1、在mapper接口中定义删除方法。
public void der(Integer id);
2、在mapper文件中,书写删除SQL语句
<delete id="del">
delete from t_student where pk_studentId=#{id};
</delete>
如果方法参数只有一个,并且是简单类型(基本数据类型、String),占位符名字可以是任意标识符。
3、书写业务接口实现类方法
public void del(Integer id) {
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
mapper.del(id);
session.commit();
session.close();
}
修改
1、定义mapper接口方法
public void update(@Param("sid") Integer id,@Param("phone") String phone);
如果方法中有多个参数,那么需要给每个参数加上别名。在mapper文件中,通过别名来引用形参的值。
2、在mapper文件中,书写执行SQL语句
<update id="update">
update t_student
set s_phone=#{phone}
where pk_studentId = #{sid};
</update>
3、书写业务方法
public void update(Integer id, String phone) {
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
mapper.update(id,phone);
session.commit();
session.close();
}
查询
在执行查询操作时,需要指定查询操作返回的结果。可以通过resultType和resultMap指定义。
resultType和resultMap的区别
resultType用于指定返回的实体类型。可以是简单类型(int,String),可以是对象类型。当返回的是实体类型时,要求属性名和列名一致。否则无法根据列名封装对象的属性。
resultMap用于定义属性和数据库列的对应关系,提高重用性,其他查询语句也可以引用。当列名和属性同名时可以不用写映射。
查询所有
1、定义mapper接口方法
public List<StudentBean> findAll();
2、书写mapper文件。
需要注意,标签必须有返回类型,返回类型可以是resultType或resultMap
在查询语句前需要定义映射
<!--定义实体类属性和列的映射,id为映射名称,type为实体类的类型-->
<resultMap id="studentMap" type="StudentBean">
<!--主键映射,propperty为属性名,column为列名-->
<id property="id" column="pk_studentId"></id>
<!--普通列-->
<result property="name" column="s_name"></result>
<result property="birthday" column="s_birthday"></result>
<result property="phone" column="s_phone"></result>
</resultMap>
书写查询语句块
<!--resultMap="studentMap"引用定义的映射-->
<select id="findAll" resultMap="studentMap">
select *
from t_student;
</select>
3、书写业务方法
public List<StudentBean> findAll() {
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
List<StudentBean> list = mapper.findAll();
session.close();
return list;
}
返回自动增长列的值,添加方法的实现
1、定义业务接口方法:
public interface IStudentService {
/**
* 添加学生
*
* @param studentBean 学生对象
* @return 学生编号
*/
public Integer add(StudentBean studentBean);
}
2、定义mapper接口方法
/**
* 添加学生
*
* @param studentBean 学生对象
*/
public void add(StudentBean studentBean);
3、书写mapper文件
<!--useGeneratedKeys="true" 表示允许使用自动增长列的值
keyProperty="id" 自动增长列的值,填充实体对象的哪个属性-->
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into t_student(s_name, s_birthday, s_phone)
values (#{name}, #{birthday}, #{phone});
</insert>
4、书写业务方法
@Override
public Integer add(StudentBean studentBean) {
SqlSession session=this.getSession();
IStudentMapper mapper=session.getMapper(IStudentMapper.class);
mapper.add(studentBean);
session.commit();
session.close();
return studentBean.getId();
}
模糊查询
1、定义mapper接口方法
/**
* 按姓名模糊查询学生
* @param name 学生姓名
* @return 学生集合
*/
public List<StudentBean> findByName(String name);
2、书写mapper文件
<select id="findByName" resultMap="studentMap">
select *
from t_student
where s_name like "%"#{name}"%";
</select>
3、书写业务方法
public List<StudentBean> findByName(String name) {
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
List<StudentBean> list = mapper.findByName(name);
session.close();
return list;
}
按时间段查询
1、定义mapper方法
/**
* 按生日时间段查询学生
*
* @param startDate 生日起始日期
* @param endDate 生日结束日期
* @return 学生集合
*/
public List<StudentBean> findByBirthday(@Param("startDate") LocalDate startDate,@Param("endDate") LocalDate endDate);
2、书写mapper文件
<select id="findByBirthday" resultMap="studentMap">
<![CDATA[
select *
from t_student
where s_birthday >= #{startDate}
and s_birthday <= #{endDate};
]]>
</select>
如果在select语句中,有>、<这样的特殊符号,尽量包在CDATA标签中的内容XML解析器不会解析,都当文本处理。
3、书写业务方法
@Override
public List<StudentBean> findByBirthday(LocalDate startDate, LocalDate endDate) {
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
List<StudentBean> list = mapper.findByBirthday(startDate, endDate);
session.close();
return list;
}
动态条件查询
1、定义mapper方法
/**
* 动态条件查询
*
* @param name 姓名
* @param startDate 生日起始日期
* @param endDate 生日结束日期
* @return 学生集合
*/
public List<StudentBean> findByItem(@Param("name") String name, @Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
}
2、书写mapper文件
<select id="findByItem" resultMap="studentMap">
select * from t_student where 1=1
<if test="name!=null and name!=''">
and s_name like "%"#{name}"%"
</if>
<if test="startDate!=null">
and s_birthday>=#{startDate}
</if>
<if test="endDate!=null">
<![CDATA[
and s_birthday<=#{endDate}
]]>
</if>
</select>
3、书写业务方法
public List<StudentBean> findByItem(String name, LocalDate startDate, LocalDate endDate) {
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
List<StudentBean> list = mapper.findByItem(name, startDate, endDate);
session.close();
return list;
}
分页
1、定义分页实体类
/**
* 分页实体类
*
* @param <T>
*/
public class CutPageBean<T> {
//当前页的数据
private List<T> list;
//总记录数
private int count;
//总页数
private int totalPage;
//每页显示的记录数
public static final int PAGRSIZE = 3;
public void setCount(int count) {
this.count = count;
this.totalPage = count % PAGRSIZE == 0 ? count / PAGRSIZE : count / PAGRSIZE + 1;
}
}
2、定义业务接口
/**
* 分页查询全部学生
*
* @param pageNO 页码
* @return 分页对象
*/
public CutPageBean<StudentBean> cutAll(int pageNO);
3、定义mapper接口
/**
* 查询当前页数据
*
* @param start 起始记录数
* @param pageSize 每页显示记录数
* @return 学生集合
*/
public List<StudentBean> cutByList(@Param("start") int start, @Param("pageSize") int pageSize);
/**
* 得到数据库表中的总记录数
*
* @return 总记录数
*/
public int getTotal();
4、书写mapper文件
<select id="cutByList" resultMap="studentMap">
select *
from t_student limit #{start},#{pageSize};
</select>
<select id="getTotal" resultType="int">
select count(*)
from t_student;
</select>
5、书写业务方法
public CutPageBean<StudentBean> cutAll(int pageNO) {
CutPageBean<StudentBean> cutPageBean = new CutPageBean<>();
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
// 封装当前页的数据
cutPageBean.setList(mapper.cutByList((pageNO - 1) * CutPageBean.PAGRSIZE, CutPageBean.PAGRSIZE));
//封装总记录数
cutPageBean.setCount(mapper.getTotal());
session.close();
return cutPageBean;
}
在myatis中,如果多个语句块,需要使用相同的SQL语句,这时可以把可以重用的SQL语句抽取出来,用标签包含。这样可以在多个语句块中,通过引用该语句中的SQL语句。
动态条件分页查询
1、定义业务接口方法
/**
* 动态条件分页查询
* @param pageNO 页码
* @param name 姓名
* @param startDate 生日起始日期
* @param endDate 生日结束日期
* @return 分页对象
*/
public CutPageBean<StudentBean> cutByItem(int pageNO, String name, LocalDate startDate, LocalDate endDate);
2、定义mapper接口方法
/**
* 动态条件分页查询当前页的数据
*
* @param start 起始记录数
* @param pageSize 每页显示记录数
* @param name 姓名
* @param startDate 生日起始日期
* @param endDate 生日结束日期
* @return 当前页数据
*/
public List<StudentBean> cutByItemList(@Param("start") int start, @Param("pageSize") int pageSize,
@Param("name") String name, @Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
/**
*动态条件分页查询总记录数
* @param name 姓名
* @param startDate 生日起始日期
* @param endDate 生日结束日期
* @return 总记录数
*/
public int cutByItemCount(@Param("name") String name,@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
3、书写mapper文件
<sql id="dynaSql">
<if test="name!=null and name!=''">
and s_name like "%"#{name}"%"
</if>
<if test="startDate!=null">
and s_birthday >=#{startDate}
</if>
<if test="endDate!=null">
<![CDATA[
and s_birthday<=#{endDate}
]]>
</if>
</sql>
<select id="cutByItemList" resultMap="studentMap">
select * from t_student where 1=1
<include refid="dynaSql"></include>
limit #{start},#{pageSize}
</select>
<select id="cutByItemCount" resultType="int">
select count(*) from t_student where 1=1
<include refid="dynaSql"></include>
</select>
4、书写业务方法
public CutPageBean<StudentBean> cutByItem(int pageNO, String name, LocalDate startDate, LocalDate endDate) {
CutPageBean<StudentBean> pageBean = new CutPageBean<>();
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
pageBean.setList(mapper.cutByItemList((pageNO - 1) * CutPageBean.PAGRSIZE, CutPageBean.PAGRSIZE, name, startDate, endDate));
pageBean.setCount(mapper.cutByItemCount(name, startDate, endDate));
session.close();
return pageBean;
}
mybatis占位符
mybatis有两种占位符:#和$;
#在生成SQL时,对于字符类型、日期类型参数,会拼装引号。
在生成SQL时,不会拼装引号,可用于order by之类的参数拼装,使用$时容易引起SQL注入。
批量操作
mybatis中,可以利用foreach标签,对集合参数进行遍历,从而进行批量操作。支持的集合包括,数组、List、Set。
1、定义mapper接口方法
/**
* 批量添加学生
*
* @param list 学生集合
*/
public void addList(@Param("list") List<StudentBean> list);
/**
* 批量删除学生
* @param idArray 学生的id数组
*/
public void delArray(@Param("idArray") int[] idArray);
2、书写mapper文件
<insert id="addList">
insert into t_student(s_name,s_birthday,s_phone) values
<!--collection要遍历的集合或数组 item表示循环变量,代表集合或数组元素 separator表示循坏间的分隔符-->
<foreach collection="list" item="student" separator=",">
(#{student.name},#{student.birthday},#{student.phone})
</foreach>
</insert>
<delete id="delArray">
delete
from t_student
where pk_studentId in (
<foreach collection="idArray" item="id" separator=",">
#{id}
</foreach>
);
</delete>
3、书写业务方法
public void addList(List<StudentBean> list) {
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
mapper.addList(list);
session.commit();
session.close();
}
@Override
public void delArray(int[] idArray) {
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
mapper.delArray(idArray);
session.commit();
session.close();
}
一对多关联映射
定义实体类:
public class DeptBean {
//部门编号
private Integer id;
//部门名字
private String name;
//负责人
private String master;
//部门员工人数
private Integer emNum;
//部门员工集合
private List<EmployeeBean> emList;
}
public class EmployeeBean {
//员工编号
private Integer id;
//员工姓名
private String name;
//员工生日
private LocalDate birthday;
//所属部门
private DeptBean dept;
}
添加员工
1、定义mapper接口方法
/**
* 添加员工
*
* @param em 员工对象
* @param deptId 员工所属部门id
*/
public void add(@Param("em") EmployeeBean em, @Param("deptId") Integer deptId);
2、书写mapper文件
<insert id="add">
insert into t_employee(e_name, e_birthday, fk_deptId)
values (#{em.name}, #{em.birthday}, #{deptId});
</insert>
3、书写业务方法
public void add(EmployeeBean em, Integer deptId) {
SqlSession session = this.getSession();
IEmployeeMapper mapper = session.getMapper(IEmployeeMapper.class);
mapper.add(em, deptId);
session.commit();
session.close();
}
查询所有员工,并查询员工所在部门名称
1、定义mapper接口
/**
* 查询所有员工,同时查询员工所在部门名称
*
* @return 员工集合
*/
public List<EmployeeBean> findAll();
2、书写mapper文件
<resultMap id="emMap" type="EmployeeBean">
<id property="id" column="pk_emId"></id>
<result property="name" column="e_name"></result>
<result property="birthday" column="e_birthday"></result>
<result property="dept.id" column="fk_deptId"></result>
<result property="dept.name" column="d_name"></result>
<result property="dept.master" column="d_master"></result>
</resultMap>
<select id="findAll" resultMap="emMap">
select e.*, d.d_name
from t_employee e,
t_dept d
where e.fk_deptId = d.pk_deptId
</select>
3、书写业务方法
public List<EmployeeBean> findAll() {
SqlSession session = this.getSession();
IEmployeeMapper mapper = session.getMapper(IEmployeeMapper.class);
List<EmployeeBean> list = mapper.findAll();
session.close();
return list;
}
按id查询员工,同时查询员工所在部门信息
1、定义mapper方法
/**
* 按编号查询员工,同时查询员工所在部门信息
*
* @param id 员工编号
* @return 员工对象
*/
public EmployeeBean findById(Integer id);
2、书写mapper文件
实现方式一:通过联表,查询实现
<resultMap id="emMap" type="EmployeeBean">
<id property="id" column="pk_emId"></id>
<result property="name" column="e_name"></result>
<result property="birthday" column="e_birthday"></result>
<result property="dept.id" column="fk_deptId"></result>
<result property="dept.name" column="d_name"></result>
<result property="dept.master" column="d_master"></result>
</resultMap>
<select id="findById" resultMap="emMap">
select e.*, d.*
from t_employee e,
t_dept d
where e.fk_deptId = d.pk_deptId
and e.pk_emId = #{id};
</select>
实现方式二:通过嵌套方式查询实现
<resultMap id="emap" type="EmployeeBean">
<id property="id" column="pk_emId"></id>
<result property="name" column="e_name"></result>
<result property="birthday" column="e_birthday"></result>
<!--dpet属性,来自findDept语句块查询结果。column表示给findDept语句块传递参数-->
<association property="dept" select="findDept" column="fk_deptId"></association>
</resultMap>
<resultMap id="dmap" type="DeptBean">
<id property="id" column="pk_deptId"></id>
<result property="name" column="d_name"></result>
<result property="master" column="d_master"></result>
</resultMap>
<select id="findDept" resultMap="dmap">
select *
from t_dept
where pk_deptId = #{id};
</select>
<select id="findById" resultMap="emap">
select *
from t_employee
where pk_emId = #{id};
</select>
添加部门,级联添加员工
1、定义业务接口方法
/**
* 添加部门,同时添加该部门的员工
*
* @param dept 部门对象
* @param emList 员工集合
*/
public void add(DeptBean dept, List<EmployeeBean> emList);
2、定义mapper接口方法
/**
* 添加部门
*
* @param dept 部门对象
*/
public void add(DeptBean dept);
/**
* 批量添加员工集合
* @param deptId 部门编号
* @param emList 员工集合
*/
public void addEmployeeList(@Param("deptId") Integer deptId,@Param("emList") List<EmployeeBean> emList);
3、书写mapper文件
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into t_dept(d_name, d_master)
values (#{name}, #{master});
</insert>
<insert id="addEmployeeList">
insert into t_employee(e_name,e_birthday,fk_deptId)
values
<foreach collection="emList" separator="," item="em">
(#{em.name},#{em.birthday},#{deptId})
</foreach>
</insert>
4、书写业务方法
public void add(DeptBean dept, List<EmployeeBean> emList) {
SqlSession session = this.getSession();
IDeptMapper mapper = session.getMapper(IDeptMapper.class);
//添加部门
mapper.add(dept);
//添加员工
mapper.addEmployeeList(dept.getId(), emList);
session.commit();
session.close();
}
删除部门,级联删除员工
1、定义mapper方法
/**
* 删除部门,同时级联删除该部门的员工
*
* @param deptId 部门编号
*/
public void delCaseCade(Integer deptId);
2、书写mapper文件
<delete id="delCaseCade">
delete
from t_employee
where fk_deptId = #{id};
delete
from t_dept
where pk_deptId = #{id};
</delete>
3、书写业务方法
public void delCaseCade(Integer deptId) {
SqlSession session = this.getSession();
IDeptMapper mapper = session.getMapper(IDeptMapper.class);
mapper.delCaseCade(deptId);
session.commit();
session.close();
}
删除部门,同时该部门员工外键置空
1、定义mapper方法
/**
* 删除部门,同时将该部门员工外键设置为null
*
* @param deptId 部门编号
*/
public void delSetNull(Integer deptId);
2、书写mapper文件
<delete id="delSetNull">
delete
from t_dept
where pk_deptId = #{id};
update t_employee
set fk_deptId=null
where fk_deptId = #{id};
</delete>
3、书写业务方法
public void delSetNull(Integer deptId) {
SqlSession session = this.getSession();
IDeptMapper mapper = session.getMapper(IDeptMapper.class);
mapper.delSetNull(deptId);
session.commit();
session.close();
}
一对多关联查询
1、定义mapper方法
/**
* 按编号查询部门,同时查询该部门的员工集合
*
* @param id 部门编号
* @return 部门对象
*/
public DeptBean findById(Integer id);
2、书写mapper文件
实现方式一:
<!--extends表示当前映射继承指定映射,从而继承父映射中定义的列和属性的映射关系-->
<resultMap id="deptMapInEm" type="DeptBean" extends="deptMap">
<!--定义关联集合映射,property表示关联集合名称-->
<collection property="emList" ofType="EmployeeBean">
<id property="id" column="pk_emId"></id>
<result property="name" column="e_name"></result>
<result property="birthday" column="e_birthday"></result>
</collection>
</resultMap>
<select id="findById" resultMap="deptMapInEm">
SELECT d.*, e.*
FROM t_dept d
LEFT JOIN t_employee e ON d.pk_deptId = e.fk_deptId
WHERE d.pk_deptId = #{id};
实现方式二:
<resultMap id="dmap" type="DeptBean" extends="deptMap">
<!--property="emList" 表示需要封装数据的属性,
select表示该属性由指定语句块查询结果封装;column表示传递给指定语句块,列的值-->
<collection property="emList" select="findEmList" column="pk_deptId"></collection>
</resultMap>
<resultMap id="emap" type="EmployeeBean">
<id property="id" column="pk_emId"></id>
<result property="name" column="e_name"></result>
<result property="birthday" column="e_birthday"></result>
</resultMap>
<!--根据部门编号查询员工集合-->
<select id="findEmList" resultMap="emap">
select *
from t_employee
where fk_deptId = #{id};
</select>
<select id="findById" resultMap="dmap">
select *
from t_dept
where pk_deptId = #{id};
</select>
3、书写业务方法
public DeptBean findById(Integer id) {
SqlSession session = this.getSession();
IDeptMapper mapper = session.getMapper(IDeptMapper.class);
DeptBean deptBean = mapper.findById(id);
session.close();
return deptBean;
}
多对多关联映射
定义实体类:
/**
* 用户实体类
*/
public class UserBean {
//用户编号
private Integer id;
//用户名
private String name;
//该用户拥有的权限集合
private List<GradeBean> gradeList;
}
/**
* 权限实体类
*/
public class GradeBean {
//权限编号
private Integer id;
//权限名称
private String name;
添加用户,同时添加用户拥有的权限
1、定义业务接口方法
/**
* 添加用户,同时添加用户拥有的权限
*
* @param user 用户对象
* @param gradeArray 权限的id数组
*/
public void addUser(UserBean user, int[] gradeArray);
2、定义mapper接口方法
/**
* 添加用户
*
* @param user 用户对象
*/
public void addUser(UserBean user);
/**
* 添加用户权限
*
* @param userId 用户id
* @param gradeList 权限id数组
*/
public void addGradeList(@Param("userId") Integer userId, @Param("gradeList") int[] gradeList);
3、书写mapper文件
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user(u_name)
values (#{name});
</insert>
<insert id="addGradeList">
insert into t_user_grade (fk_userId,fk_gradeId) values
<foreach collection="gradeList" item="gradeId" separator=",">
(#{userId},#{gradeId})
</foreach>
</insert>
4、书写业务方法
public void addUser(UserBean user, int[] gradeArray) {
SqlSession session = this.getSession();
IUserMapper mapper = session.getMapper(IUserMapper.class);
mapper.addUser(user);
mapper.addGradeList(user.getId(), gradeArray);
session.commit();
session.close();
}
删除用户,同时删除用户对应的权限
1、定义mapper接口方法
/**
* 删除用户,同时删除该用户的权限
*
* @param userId 用户id
*/
public void delUser(Integer userId);
2、书写mapper文件
<delete id="delUser">
delete
from t_user_grade
where fk_userId = #{id};
delete
from t_user
where pk_userId = #{id};
</delete>
3、书写业务方法
public void delUser(Integer userId) {
SqlSession session = this.getSession();
IUserMapper mapper = session.getMapper(IUserMapper.class);
mapper.delUser(userId);
session.commit();
session.close();
}
修改用户权限
1、定义mapper接口方法
/**
* 修改用户权限
*
* @param userId 用户编号
* @param newGradeArray 新权限id数组
*/
public void updateGrade(@Param("userId") Integer userId, @Param("newGradeArray") int[] newGradeArray);
2、书写mapper文件
<delete id="delUser">
delete
from t_user_grade
where fk_userId = #{id};
delete
from t_user
where pk_userId = #{id};
</delete>
<update id="updateGrade">
delete
from t_user_grade
where fk_userId = #{userId};
insert into t_user_grade(fk_userId,fk_gradeId) values
<foreach collection="newGradeArray" item="gradeId" separator=",">
(#{userId},#{gradeId})
</foreach>
</update>
3、书写业务方法
public void updateGrade(Integer userId, int[] newGradeArray) {
SqlSession session = this.getSession();
IUserMapper mapper = session.getMapper(IUserMapper.class);
mapper.updateGrade(userId, newGradeArray);
session.commit();
session.close();
}
多对多关联查询
查询用户,同时查询该用户拥有的权限集合
1、书写mapper接口方法
/**
* 按id查询用户,同时查询该用户拥有的权限集合
*
* @param userId 用户id
* @return 用户对象
*/
public UserBean findById(Integer userId);
2、书写mapper文件
实现方式一:联表,定义resultMap映射
<resultMap id="umap" type="UserBean">
<id property="id" column="pk_userId"></id>
<result property="name" column="u_name"></result>
<collection property="gradeList" ofType="GradeBean">
<id property="id" column="pk_gradeId"></id>
<result property="name" column="g_name"></result>
</collection>
</resultMap>
<select id="findById" resultMap="umap">
SELECT u.*, g.*
FROM t_user u,
t_user_grade ug,
t_grade g
WHERE u.pk_userId = ug.fk_userId
AND g.pk_gradeId = ug.fk_gradeId
AND u.pk_userId = 1;
</select>
实现方式二:嵌套查询
<resultMap id="userMap" type="UserBean">
<id property="id" column="pk_userId"></id>
<result property="name" column="u_name"></result>
<collection property="gradeList" select="findGrade" column="pk_userId"></collection>
</resultMap>
<resultMap id="gmap" type="GradeBean">
<id property="id" column="pk_gradeId"></id>
<result property="name" column="g_name"></result>
</resultMap>
<select id="findGrade" resultMap="gmap">
select g.*
from t_user_grade ug,
t_grade g
where ug.fk_gradeId = g.pk_gradeId
and ug.fk_userId = #{userId};
</select>
<select id="findById" resultMap="userMap">
select *
from t_user
where pk_userId = #{userId};
</select>
3、书写业务方法
public UserBean findById(Integer userId) {
SqlSession session = this.getSession();
IUserMapper mapper = session.getMapper(IUserMapper.class);
UserBean userBean = mapper.findById(userId);
session.close();
return userBean;
}
mybatis注解
使用mybatis注解开发,可以在定义mapper接口时书写SQL语句,可以省去mapper文件。简洁方便。但是比较复杂的SQL和动态SQL还是建议书写mapper文件。
@Insert("insert into t_student(s_name,s_birthday,s_phone)" +
"values(#{name},#{birthday},#{phone})")
public void add(StudentBean studentBean);
@Delete("delete from t_student where pk_studentId=#{id}")
public void del(Integer id);
@Update("update t_student set s_phone=#{phone} where pk_studentId=#{id}")
public void update(@Param("id") Integer id, @Param("phone") String phone);
查询语句,最好在mapper文件定义映射,方便重用。
<resultMap id="studentMap" type="StudentBean">
<id property="id" column="pk_studentId"></id>
<result property="name" column="s_name"></result>
<result property="birthday" column="s_birthday"></result>
<result property="phone" column="s_phone"></result>
</resultMap>
@Select("select * from t_student")
@ResultMap("studentMap")
public List<StudentBean> findAll();
@Select("select * from t_student where s_name like \"%\"#{name}\"%\"")
@ResultMap("studentMap")
public List<StudentBean> findByName(String name);
@Select("select * from t_student where s_birthday>=#{startDate} and s_birthday<=#{endDate}")
@ResultMap("studentMap")
public List<StudentBean> findByBirthday(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
mybatis缓存
mybatis的缓存是指,将前一次查询的结果先在内存中存储。如果下一次查询和上一次查询是相同的结果,则不再进行数据库查询操作,而是从缓存中取出并返回。
mybatis的缓存分为一级缓存和二级缓存
一级缓存,也称为session级缓存,随session会话产生而产生,随session会话关闭而消失。在同一个会话session中,执行查询语句时,默认会将查询结果放在一级缓存中。如果会话不关闭,再查询相同的数据时,就直接从一级缓存中获取,而不用再执行查询操作。
public StudentBean findById(Integer id) {
SqlSession session = this.getSession();
IStudentMapper mapper = session.getMapper(IStudentMapper.class);
StudentBean studentBean = mapper.findById(id);//第一次查询,发出sql请求,查询数据库,并将查询结果放在一级缓存中
StudentBean s1 = mapper.findById(id);//第二次查询,由于查询的是相同的数据,直接从一级缓存中获取,而不再执行查询操作
System.out.println(s1==studentBean);//true,两次得到的是同一个对象
session.close();
return studentBean;
}
会发出两条SQL查询,当session关闭,一级缓存消失,再查询时,会重新建立连接,重新执行查询操作。
System.out.println(service.findById(1));
System.out.println(service.findById(1));
二级缓存,称为应用级缓存,可以在不同用户的session中,共享查询数据。流程:第一个用户查询数据库,将查询结果同时存放进一级缓存和二级缓存。当第一个用户session关闭后,一级缓存消失,但二级缓存不会消失。第二个用户如果查询相同数据时,会先在一级缓存中查询数据,如果没有,再查询二级缓存中的数据。如果还没有,再去做数据库查询操作。
二级缓存的实现:
1、mybatis.cfg.xml中,开启二级缓存
<settings>
<!--开启二级缓存,默认开启-->
<setting name="cacheEnabled" value="true"/>
</settings>
需要放入二级缓存中保存的JavaBean,实现Serializable序列化接口
2、在mapper映射文件中,配置二级缓存
<cache/>
3、在查询语句块中,设置查询结果需要进入二级缓存。
<select id="findById" result="linkMap" useCache="true">
select * from t_link where pk_linkId=#{id};
</select>