05mybatis

  • 2021-12-27
  • Admin

一.认识MyBatis

1)Mybatis是什么

MyBatis 是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC代码和手动设置参数以及获取结果集,它可以使用简单的XML或注解来配置和映射SQL信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
  • 1

2)ORM是什么

对象-关系映射(OBJECT/RELATIONALMAPPING,简称ORM),是随着面向对象的软件开发方法发展而产生的。用来把对象模型表示的对象映射到基于SQL 的关系模型数据库结构中去。这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的 SQL 语句打交道,只需简单的操作实体对象的属性和方法 。ORM 技术是在对象和关系之间提供了一条桥梁,前台的对象型数据和数据库中的关系型的数据通过这个桥梁来相互转化。
  • 1

3)ORM框架和MyBatis的区别

对比项MybatisHibernate
市场占有率
适合的行业互联网 电商 项目传统的(ERP CRM OA)
性能
Sql灵活性
学习门槛
Sql配置文件全局配置文件、映射文件全局配置文件、映射文件
ORM半自动化完全的自动化
数据库无关性

4)设计模式的类型

总体来说,设计模式分为三类23种

  • 创建型(5种) : 工厂模式、抽象工厂模式、单例模式、原型模式、构建者模式
  • 结构型(7种):适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式
  • 行为型(11种):模板方法模式、策略模式、观察者模式、中介者模式、状态模式、责任链模式、命令模式、迭代器模式、访问者模式、解释器模式、备忘录模式

二.应用篇

1)mapper代理开发方式

代理分为静态代理动态代理。此处先不说静态代理,因为Mybatis中使用的代理方式是动态代理。动态代理分为两种方式:

  • 基于JDK的动态代理–针对有接口的类进行动态代理
  • 基于CGLIB的动态代理–通过子类继承父类的方式去进行代理。

2)自增主键新增时,返回id

  • 注解方式

    /*
    * statement="select max(empNo)+1 as myNo from emp":表示定义的子查询语句
    * before=true:表示在之前执行,booler类型的,所以为true
    * keyColumn="myNo":表示查询所返回的类名
    * resultType=int.class:表示返回值得类型
    * keyProperty="empNo" :表示将该查询的属性设置到某个列中,此处设置到empNo中
    * 注意:使用MySQL的last_insert_id()函数时,before必为false,也就是说必须先插入然后执行last_insert_id()才能获得刚刚插入数据的ID
    */
    @Insert("insert into people(name) values(#{name})")
    @SelectKey(statement = "SELECT LAST_INSERT_ID()",keyColumn = "id", keyProperty = "id",
               resultType = Integer.class, before = false)
    void insertPeople(People people);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • xml方式

    <insert id="insertPeople1">
        <selectKey order="AFTER" keyColumn="id" keyProperty="id" resultType="integer">
            select last_insert_id()
        selectKey>
        insert into people(name) values(#{name})
    insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

3)一对一,一对多查询

一对一

  • xml配置

DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.monkey.mybatis.dao.OrderDao">
    <resultMap id="oneForOne" type="com.monkey.mybatis.dto.OneForOneDTO">
        <id column="p_id" property="pId"/>
        <result column="order_name" property="orderName"/>
        <result column="order_money" property="orderMoney"/>
        <association property="people" javaType="com.monkey.mybatis.model.People">
            <id column="id" property="id"/>
            <result column="name" property="name"/>
        association>
    resultMap>

    <select id="selectOrder" resultType="com.monkey.mybatis.dto.OneForOneDTO" resultMap="oneForOne">
        select
            a.p_id,
            a.order_name,
            a.order_money,
            b.id,
            b.name
        from `order` a
        left join people b on a.p_id=b.id
    select>
mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 注解

@Mapper
public interface OrderDao {
    @Select("        select\n" +
            "            a.p_id,\n" +
            "            a.order_name,\n" +
            "            a.order_money,\n" +
            "            b.id,\n" +
            "            b.name\n" +
            "        from `order` a\n" +
            "        left join people b on a.p_id=b.id")
    @Results(value = {
            @Result(property = "pId", column = "p_id", id = true),
            @Result(property = "orderName", column = "order_name"),
            @Result(property = "orderMoney", column = "order_money"),
            @Result(property = "people",  one = @One(select = "selectPeople"), column = "id"),
    })
    List<OneForOneDTO> selectOrder1();

    @Select("select * from people where id=#{id}")
    People selectPeople(int id);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

一对多

  • xml

DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.monkey.mybatis.dao.PeopleDao">
    <resultMap id="oneForSome" type="com.monkey.mybatis.dto.OneForSomeDTO">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <collection property="orders" ofType="com.monkey.mybatis.model.Order">
            <result column="order_name" property="orderName"/>
            <result column="order_money" property="orderMoney"/>
        collection>
    resultMap>

    <select id="selectPeople" resultType="com.monkey.mybatis.model.People" resultMap="oneForSome">
        select
            a.id,
            a.name,
            b.order_name as order_name,
            b.order_money as order_money
        from people a
        left join `order` b on b.p_id=a.id
    select>
mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 注解
@Mapper
public interface PeopleDao {
    @Select("select id,name from people")
    @Results(value = {
            @Result(property = "id", column = "id", id = true),
            @Result(property = "name", column = "name"),
            @Result(property = "orders", javaType = List.class,
                    many = @Many(select = "selectOrder"), column = "id"),
    })
    List<OneForSomeDTO> selectPeople1();

    @Select("select p_id as pId, order_name as orderName,order_money as orderMoney 
            from `order` where p_id = #{id}")
    List<Order> selectOrder(@Param("id") int id);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

4)#{}和${}区别

  • 区别1
#{}  :相当于JDBC SQL语句中的占位符? (PreparedStatement)
${}  : 相当于JDBC SQL语句中的连接符合 + (Statement)
  • 1
  • 2
  • 区别2
#{}  : 进行输入映射的时候,会对参数进行类型解析(如果是String类型,那么SQL语句会自动加上’’)
${}  :  进行输入映射的时候,将参数原样输出到SQL语句中
  • 1
  • 2
  • 区别3
#{}  : 如果进行简单类型(String、Date、8种基本类型的包装类)的输入映射时,#{}中参数名称可以任意
${}  :  如果进行简单类型(String、Date、8种基本类型的包装类)的输入映射时,${}中参数名称必须是value
  • 1
  • 2
  • 区别4
${} : 存在SQL注入问题 ,使用OR 1=1 关键字将查询条件忽略
  • 1

5)延迟加载

1. 什么是延迟加载

  • MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟规则推迟对关联对象的select查询。延迟加载可以有效的减少数据库压力
  • Mybatis的延迟加载,需要通过resultMap标签中的associationcollection子标签才能演示成功。
  • Mybatis的延迟加载,也被称为是嵌套查询,对应的还有嵌套结果的概念,可以参考一对多关联的案例。
  • 注意:MyBatis的延迟加载只是对关联对象的查询有延迟设置,对于主加载对象都是直接执行查询语句的。

2. 延迟加载的分类

  • 延迟加载的分类
    MyBatis根据对关联对象查询的select语句的执行时机,分为三种类型:直接加载、侵入式加载与深度延迟加载
    1.直接加载: 执行完对主加载对象的select语句,马上执行对关联对象的select查询。
    2.侵入式延迟:执行对主加载对象的查询时,不会执行对关联对象的查询。但当要访问主加载对象的某个属性(该属性不是关联对象的属性)时,就会马上执行关联对象的select查询
    3.深度延迟:执行对主加载对象的查询时,不会执行对关联对象的查询。访问主加载对象的详情时也不会执行关联对象的select查询。只有当真正访问关联对象的详情时,才会执行对关联对象的select查询。

    延迟加载策略需要在Mybatis的全局配置文件中,通过标签进行设置。

3. 代码

  • 直接加载
<settings>
    
    <setting name="lazyLoadingEnabled" value="false"/>
settings>
  • 1
  • 2
  • 3
  • 4
  • 侵入式加载
<settings>
    
    <setting name="lazyLoadingEnabled" value="true"/>
    
    <setting name="aggressiveLazyLoading" value="true"/>
settings>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 深度延迟加载
<settings>
    
    <setting name="lazyLoadingEnabled" value="true"/>
    
    <setting name="aggressiveLazyLoading" value="false"/>
settings>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4.N+1问题

  • 深度延迟加载的使用会提升性能
  • 如果延迟加载的表数据太多,此时会产生N+1问题,主信息加载一次算1次,而从信息是会根据主信息传递过来的条件,去查询从表多次

6)mybatis缓存

  • 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
  • 二级缓存是**Mapper(namespace)**级别的缓存。多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

一级缓存

Mybatis默认开启了一级缓存

1. 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据
库查询用户信息,将查询到的用户信息存储到一级缓存中。
2. 如果中间sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓
存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
3. 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从
缓存中获取用户信息。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

二级缓存

1. 第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区
域内。
2. 第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息。会去对应的二级
缓存内取结果。
3. 如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会
清空该namespace下的二级缓存。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 开启二级缓存

<settings>
    <setting name="cacheEnabled" value="true"/>
settings>
  • 1
  • 2
  • 3
  • 4

<cache>cache>
  • 1
  • 2
  • 实现序列化
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,比如说存储到文件系统中,所以需要给缓存的对象执行序列化。
  • 1

7)动态SQL

1.if标签

<select id="findUserList" parameterType="queryVo" resultType="user">
	SELECT * FROM user where 1=1
	<if test="user != null">
		<if test="user.username != null and user.username != ''">
			AND username like '%${user.username}%'
		if>
	if>
select>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.where标签

<select id="findUserList" parameterType="queryVo" resultType="user">
	SELECT * FROM user
	
		<where>
			<if test="user != null">
				<if test="user.username != null and user.username != ''">
					AND username like '%${user.username}%'
				if>
			if>
		where>
select>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.sql片段

在映射文件中可使用sql标签将重复的sql提取出来,然后使用include标签引用即可,最终达到sql重用的目的

  • 将where条件抽取出来
<sql id="query_user_where">
        <if test="user != null">
            <if test="user.username != null and user.username != ''">
                AND username like '%${user.username}%'
            if>
        if>
sql>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 使用include引用

<select id="findUserList" parameterType="queryVo" resultType="user">
    SELECT * FROM user
    
 

联系站长

QQ:769220720

Copyright © SibooSoft All right reserved 津ICP备19011444号