MyBatis

MyBatis

ORM框架

什么是ORM?

Object Relation Manager对象关系映射,负责对象类型与数据库类型之间的映射处理

MyBatis 与 Hibernate的区别

Mybatis

  • 半自动映射框架
  • Sql需要自己编写,映射关系需要自己配置

Hibernate

  • 全自动映射框架
  • Sql需要自己写,映射关系需要自己配置

为什么要使用Mybatis?

  • Hibernate虽然封装了Sql,简化了开发,但是不能优化sql,如果我们想写一个高级的sql,需要去学HQL语言(Hibernate的操控数据库的语言),增加了开发难度
  • Hibernate还是一个全映射框架,假如你只需要查一个字段,他也会查出所有的字段,全部返回给你

MyBatis工作原理

重要

  1. 读取全局配置文件 - MyBatis-config.xml

  2. 加载映射文件 - xxxMapper.xml

  3. 构造会话工厂 - SqlSessionFactory 负责生成SqlSession对象

  4. 创建会话对象 - 由SqlSessionFactory创建SqlSession对象,该对象中包含了执行SQL语句的所有方法

  5. Executor 执行器

    MyBatis定义了一个Executor接口操作数据库,根据SqlSession传递的参数动态地生成需要执行的Sql语句,同时负责查询缓存的维护

  6. MappedStatement对象

    Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息

  7. 输入参数映射

    输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程

  8. 输出参数映射

    输出结果类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程

全局配置文件

根元素configuration

properties

加载Properties外部文件配置

settings

配置Mybatis运行时的行为

  • CacheEnabled 配置二级缓存是否开启
  • lazyLoading 配置是否可以延迟加载
  • useColumnLable 使用列标签代替列名
  • defaultStatemntTimeOut 默认的会话等待时间
  • mapUnderscoreToCamelCase 下划线转为驼峰

typeAliases

  • 设置别名
  • 别名部分大小写
  • 也能用注解@Alias

typeHandlers

处理对象与数据库数据类型之间的映射关系

ObjectFactory

对象工厂

Plugins

载入插件,比如拦截调用的一些插件

environments

  • 配置数据源
    • UNPOOLED 不使用池
    • POOLED 使用池
    • JNDI
  • 配置事务
    • 使用Spring事务管理,所以这里不需要管

databaseIdProvider

用来配置不通的数据库

mappers

配置映射文件所在的位置

映射文件

mapper.xml文件

  • insert
    • id
    • parameterType 可以省略
    • 返回值默认有三种integer、long、boolean
  • update 同上
  • delete 同上
  • select
    • resultType
      • 配置返回数据的类型
      • resultType=”map” 返回一个key为列名,value为值的一个map对象

参数处理

  • 对于单个参数,不做特殊处理,直接返回结果
  • 对于多个参数,需要用@Param配置名称,如果不使用注解,那么需要使用param1、param2来获取
  • 如果参数很多,和POJO的类型一样,那么直接传POJO即可
  • 如果很多,也不常用,也可以传Map
  • 如果很多,经常使用,可以编写TO类

#{}与${}的区别

  • #{}相当于preStatement调用,可以避免Sql注入
    preparestatement在程序第一次查询数据库之前sql语句就被数据库进行了分析、编译、优化以及具体的查询计划也都形成了,之后参数进来的时候不会被分析处理为指令

    简单来说就是:不让参数参与编译阶段,而是使用占位符代替,从而解决了sql注入问题

  • ${}可以用在一些不能使用#{}的时候,比如排序

resultmap实现高级映射

  • association
    • 实现分步查询
    • 用在一对一关系
    • 在此基础上可以实现延迟加载 即只有用到了才会执行这个Sql
  • collection
    • 实现一对多关系映射
    • 也可以实现延迟加载
    • 使用ofType属性配置集合中元素的类型

缓存

缓存的本质,就是一个map对象

Mybatis有两级缓存

一级缓存

  • 属于SqlSession级别的缓存,同一次数据库会话使用同一个SqlSession
  • 失效的情况,有四种
    • 使用两个不同的SqlSession
    • 使用相同的SqlSession
      • 查询条件不同
      • 清除了缓存
      • 在两次查询期间执行了增删改操作

二级缓存

  • 属于namespace级别的缓存,即一个mapper文件对应一个二级缓存(比如学生Mapper一个、专业Mapper一个等等)
  • 当sqlSession提交或者关闭后,它的数据就会存放在二级缓存中

查询顺序

先查二级缓存,再查一级缓存,如果一二级缓存都没有命中,查数据库

二级缓存配置cache

eviction配置回收策略

  • LRU默认
  • FIFO
  • SOFT 回收软引用
  • WEAK 回收弱引用

readOnly

  • true mybatis认为你不会做修改操作,然后每次都会直接返回缓存中的值
  • false (默认) mybatis认为你会做修改,所以每次返回都是返回缓存中反序列化克隆后的结果

flushInterval

配置多久时间清空一次缓存,默认不清空

type

我们可以自己实现缓存,实现接口cache,然后将实现类的全限定类名作为type的值即可

#{}和${}

#{}是预编译处理,是占位符,${}是字符串替换,是拼接符

  • Mybatis处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement来赋值
  • Mybatis在处理${}时,就是把${}替换成变量的值Statement来赋值
  • #{}的变量替换是在DBMS中,变量替换后,#{}对应的变量自动加上单引号
  • ${}的变量替换是在DBMS外,变量替换后,${}对应的变量不会加上单引号
  • 使用#{}可以有效的防止SQL注入,提高系统安全性
    1. 占位符会将输入的值视为参数数据而不是SQL代码
    2. 拼接符会当做SQL代码,如果被恶意注入比如输入SELECT * FROM users WHERE username = ‘admin’; DROP TABLE users; *–’;,这里的- -*是SQL语句的注释符号,会导致后面的内容被忽略