mybatis

  • Post author:
  • Post category:其他




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&amp;characterEncoding=utf8&amp;useUnicode=true&amp;useSSL=false&amp;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>



版权声明:本文为m0_69836134原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。