Mybatis学习笔记

Mybatis学习

概念了解

一个基于ORM的轻量级半自动持久层框架

  • orm
    • Objcet/Relation Mapping 对象关系映射
    • 把关系数据库包装成面向对象的模型
    • 实现效果:把对持久化对象的保存、修改、删除等操作,准换为数据库的操作
  • 轻量级
    • 占用资源少
  • 半自动
    • 相对于hibernate的全自动,Mybatis需要自己编写sql文件
  • 持久层
    • 什么意思,不知道

Mapper接口开发遵循规范

  • Mapper.xml文件的nameSpace与mapper接口的全限定名相同
  • Mapper接口方法名和mapper.xml中定义的每个statement的id相同
  • 接口输入参数类型和parameterType类型相同
  • 接口输出参数类型和resultType类型相同

Mybatis四大组件

  • Executor
  • StatementHandler
  • ParameterHandler
  • ResultSetHanler

配置文件解析

Properties

额外配置信息

   <!--加载外部properties文件-->
    <properties resource="jdbc.properties"> </properties>

properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///zdy_mybatis
jdbc.username=root
jdbc.password=root
typeAliases

类型别名

<!--给实体类的全限定类名给别名-->
    <typeAliases>
        <!--<typeAlias type="com.lagou.pojo.User" alias="User"></typeAlias>-->
        <!--常用包装类mybatis已经起好别名-->
        <!--批量起别名: 该包下所有的类的类名:别名不区分大小写-->
        <package name="com.lagou.pojo"/>
    </typeAliases>

mybatis已经为一些常用类型起了别名

别名 数据类型
string String
long Long
int Integer
double Double
boolean Boolean
environments

数据库环境配置

   <!--运行环境-->
    <environments default="development"> 
        <environment id="development">
            <!--当前事务交由JDBC管理-->
            <transactionManager type="JDBC"/>
            <!--当前使用mybatis提供的连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
mapper

加载映射文件

  <mappers>
        <!-- 加载单个映射配置文件 -->
        <mapper resource="com/lagou/mapper/UserMapper.xml"/>
        <!-- 加载该包下的全部配置文件 -->
        <!--要保证同包同名-->
        <!-- com.lagou.dao.OrderMapper.java 对应 com.lagou.dao.OrderMapper.xml -->
        <package name="com.lagou.dao"/>
   </mappers>

动态sql

if

根据实体类取值,使用不同SQL语句进行查询

<select id="findByCondition" parameterType="user" resultType="user">
        select * from User
        <where>
            <if test="id!=0">and id=#{id}</if>
            <if test="username!=null">and username=#{username}</if>
        </where>
    </select>
foreach

循环执行sql的拼接操作

 <select id="findByIds" parameterType="list" resultType="User">
        <include refid="selectUser"></include>
        <where>
            <foreach collection="array" separator="," open="id in (" close=")" item="id">
                #{id}
            </foreach>
        </where>
    </select>

标签属性:

  • collection 代表要遍历的元素,分三种情况, array(array), list(list), map 需要的value对应的key(key值 )
  • open 代表语句的开头
  • close 结束部分
  • item 遍历的每个元素,生成的变量名
  • sperator 分割符
SQL片段抽取

抽取重复sql语句,使用include引用,达到sql复用

 	<sql id="selectUser">
        select *
        from user
    </sql>
    
    <select id="findAll" resultType="user">
        <include refid="selectUser"></include>
    </select>

复杂映射开发

一对一

方式一: 通过association

  <resultMap id="OrderAndOrder" type="Order">
        <result column="id" property="id"></result>
        <result column="ordertime" property="orderTime"></result>
        <result column="total" property="total"></result>
        <result column="uid" property="uid"></result>
        <association property="user" javaType="User">
            <result column="uid" property="id"></result>
            <result column="username" property="username"></result>
            <result column="password" property="password"></result>
            <result column="birthday" property="birthday"></result>
        </association>
    </resultMap>

方式二: 通过 .

 <resultMap id="orderMap" type="com.lagou.pojo.Order">
        <!--字段名和属性名相同的可以不写,任然可以赋值-->
        <result column="uid" property="user.id"></result>
        <result column="username" property="user.username"></result>
        <result column="password" property="user.password"></result>
        <result column="birthday" property="user.birthday"></result>
    </resultMap>
一对多

collection 标签,配置一对多

  <resultMap id="UserMap" type="com.lagou.pojo.User">
        <result property="id" column="uid"></result>
        <result property="username" column="username"></result>
        <collection property="orderList" ofType="com.lagou.pojo.Order">
            <result property="id" column="oid"></result>
            <result property="orderTime" column="ordertime"></result>
            <result property="total" column="total"></result>
        </collection>
    </resultMap>

缓存

一级缓存是SqlSession级别的缓存,不同sqlSession之间的缓存数据区域(是相互不影响的

二级缓存是mapper级别的缓存, 多个sqlSession可以共用二级缓存,二级缓存跨SqlSession

一级缓存

一级缓存默认开启

二级缓存

二级缓存需要手动开启

开始方式:

mybatis配置文件

  <!-- 开启二级缓存-->
    <settings>
      	<!--默认值为true -->
        <setting name="cacheEnabled" value="true"/>
    </settings>

具体的mapper配置文件

    <!--标识  这个namespace开启二级缓存 -->
    <cache></cache>
二级缓存整合redis
Sql标签中的缓存配置

flushCache 是否刷新缓存

useCache 是否使用缓存

    <!--flushCache 默认true, 刷新缓存-->
    <!--useCache=false 禁用缓存,避免脏读,直接从数据库获取 -->
    <select id="select" resultType="com.lagou.pojo.User" flushCache="false" useCache="false">
        select *
        from user
    </select>

Mybatis插件

对mybatis来说,插件就是拦截器, 用来增强核心对象的功能, 借助底层的动态代理实现

自定义插件

实例实现:

实现Interceptor接口

/**
 * 自定义插件
 * @author fjhua
 * @create 2021-04-18 22:01
 */
@Intercepts({
        @Signature(type = StatementHandler.class,    //拦截的目标对象
                method = "prepare",                   //拦截的目标方法
                args = {Connection.class, Integer.class}) // 拦截目标方法的参数
})
public class MyPlugin implements Interceptor {
    /**
     * 拦截方法: 只要被拦截的目标对象的目标方法被执行时, 每次都会执行intercept方法
     * @param invocation  拦截的方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("对方法增强");
        return invocation.proceed();
    }

    /**
     * 主要是为了把当前的拦截器生成的代理存到拦截器链中
     * @param target
     * @return
     */
    @Override
    public Object plugin(Object target) {
        Object wrap = Plugin.wrap(target, this);
        return wrap;
    }

    /**
     * 获取配置文件参数
     * @param properties 配置文件中 property 的键和值
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("获取到的配置文件参数: " + properties);
        // 日志打印:  获取到的配置文件参数: {name=tom}
    }
}

配置文件注册插件

    <!--注意该标签的位置, 需要在typeAliases标签之后 -->
    <plugins>
        <plugin interceptor="com.lagou.config.MyPlugin">
            <property name="name" value="tom"/>
        </plugin>
    </plugins>
pageHelper
通用mapper

延迟加载

基于嵌套查询实现延迟加载

优缺点

选择策略

实现/局部延迟/全局延迟

实现原理

延迟加载配置的标签和属性

sql是否延迟加载各种策略的执行(源码剖析)

相关设计模式

P79

构建者模式

使用多个简单的对象一步一步构建成一个复杂的对象

工厂模式

简单工厂模式

接口和具体产品

public abstract class Book {
    public void read() {
        System.out.println("开始读书");
    }

}

class MathBook extends Book {
    @Override
    public void read() {
        super.read();
        System.out.println("读数学书");
    }
}

class ChineseBook extends Book {
    @Override
    public void read() {
        super.read();
        System.out.println("读语文书");
    }
}

工厂类及测试

public class BookFactory {

    public static Book build(String bookType) {
        Book book = null;

        switch (bookType) {
            case "math":
                book = new MathBook();
                break;
            case "chinese":
                book = new ChineseBook();
                break;

        }
        return book;
    }

    public static void main(String[] args) {
        Book book = BookFactory.build("math");
        book.read();
    }
    /**
     * 开始读书
     * 读数学书
     */
}
代理模式

接口

public interface Book {
    void read();
}

实现类

public class MathBook implements Book {
    @Override
    public void read() {
        System.out.println("读数学书");
    }
}

代理

public class BookProxy implements InvocationHandler {

    private Book book;

    public BookProxy(Book book) {
        this.book = book;
    }

    public Book getProxyBook() {
        Object proxyInstance = Proxy.newProxyInstance(book.getClass().getClassLoader(), book.getClass().getInterfaces(), this);
        return (Book) proxyInstance;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法增强");
        Object invoke = method.invoke(book, args);
        System.out.println("方法后置增强");
        return invoke;
    }
}

测试

class TestBook {
    public static void main(String[] args) {
        MathBook mathBook = new MathBook();
        mathBook.read();
        System.out.println("===========");
        Book proxyBook = new BookProxy(new MathBook()).getProxyBook();
        proxyBook.read();
    }
    /**
     * 读数学书
     * ===========
     * 方法增强
     * 读数学书
     * 方法后置增强
     */
}
posted @ 2021-04-19 22:49  度亚  阅读(51)  评论(0)    收藏  举报