Mybatis

211 阅读11分钟

MyBatis特性

  1. MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
  2. MyBatis避免了几乎所有的JDBC代码和手动参数设置
  3. Mybatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java和POJO(Plan Old Java Object,普通的Java对象)映射成数据库中的记录
  4. MyBatis是一个半自动的ORM(Object Relation Mapping)框架

MyBatis和其他持久化层技术的比较

  • Hibernate 和 JPA

    • 程序中长难复杂的SQL需要绕过框架
    • 内部自动生产的SQL,不容易做特殊优化
    • 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难
    • 反射操作太多,导致数据库性能下降
  • MyBatis

    • 轻量级、性能出色
    • SQL和Java编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据、
    • 开发效率稍逊于Hibernate但是完全可以接受

创建MyBatis核心配置文件

习惯上命名为mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。将来整合Spring之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴。 核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息 核心配置文件存放的位置是src/main/resources目录下

创建Mapper接口

MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类。

  • 创建实体类时一定要保证属性名和表的属性一致

相关概念ORM

  • 对象:Java的实体类对象
  • 关系:关系型数据库
  • 映射:二者之间的对应关系
Java概念数据库概念
属性字段/列
对象记录/行

Mapper面向接口编程的两个一致

  1. 映射文件的namespace要和mapper接口的全类名保持一致
  2. 映射文件中的SQL语句的id要和mapper接口中的方法名一致

查询功能的标签必须设置resultType或者resultMap

  • resultType: 设置默认的映射关系
  • resultMap: 设定自定义的映射关系(字段名和属性名不一样/一对多/多对一)

核心配置文件之environment

  • transactionManager:设置事务管理方式

    • 属性:
      • type="JDBC/MANNAGED"
      • JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,事务的提交或回滚需要手动处理
      • MANNAGED:表示被管理,例如spring
  • dataSource:配置数据源

    • 属性:
    • type:设置数据源的类型
    • type:“POOLED/UNPOOLED/JNDI"
    • POOLED:表示使用数据库连接池缓存数据库连接
    • UNPOOLED:表示不使用数据库连接池
    • JNDI:表示使用上下文中的数据源

image.png

MyBatis中核心配置文件的标签顺序:

image.png

设置类型别名 类型别名不区分大小写

<typeAliases>
    <typeAlias type="com.sundwich.mybatis.pojo.User" alias="User"></typeAlias>
    
    <!--以包为单位,给包下面的所有类型设置默认的类型别名,即类名切不区分大小写-->
    <package name="com.sundwich.mybatis.pojo"/>
<typeAliases>

<mappers>
<!--<mapper resource="mapper/UserMapper.xml"/>-->
<!--
    以包为单位引入映射文件
    要求:
    1. mapper接口所在的包要和映射文件所在的包一致
    2. mapper接口要和映射文件的名字一致
-->
</mappers>

//如果不写alias=”User“ 如果不设置该属性,那么该类型拥有默认的别名,即类名且不区分大小写

MyBatis获取参数值的两种方式(重点)

MyBatis获取参数值的两种方式:${}和#{}

  • ${}本质是字符串拼接 注意要手动加单引号

  • #{}本质占位符

  • MyBatis获取参数的各种情况

  1. mapper接口方法的参数为单个的字面量类型

    • 可以通过{}和#{}以任意的字符串获取参数值,但是需要注意{}的单引号问题 ‘${}’
  2. MyBatis会将这些参数放到一个map集合中,以两种方式进行存储

    • 以arg0、arg1...为键,以参数为值
    • 以param1、param2...为键,以参数为值
    • 因此只需要通过#{} and 以键的方式访问值即可,但是需要注意{}以键的方式访问值即可,但是需要注意{}的单引号
  3. 若mapper接口方法的参数有多个时,可以手动放到一个map中

    • 只需要通过#{} and 以键的方式访问值即可,但是需要注意{}以键的方式访问值即可,但是需要注意{}的单引号
  4. mapper接口方法的参数是一个实体类类型的参数

    • 只需要通过#{}以属性的方式访问属性值即可,但是需要注意${}的单引号问题
  5. 使用@Param注解命名参数

    • 此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
      • 以@Param注解的值为键,以参数为值
      • 以param1、param2...为键

MyBatis各种查询功能

  1. 若查询出的数据只有一条
    1. 可以通过实体类对象
    2. 可以通过集合来接收结果
    3. 可以通过map集合接收:字段名为key,值为value
  2. 若查询出的数据有多条
    1. 可以通过实体类list集合

    2. 可以通过map类型的list接收

    3. 可以在mapper接口的方法上添加@Mapkey注解,此时就可以将每条数据转换的map集合作为值,以某个字段的值作为键,放在同一个map中 exp: @Map("id")

    注意:一定不能通过实体类对象接收结果,此时会抛异常

MyBatis中设置了默认的类型别名

java.lang.Integer-->int,integer

int-->_int,_integer

Map-->map

string-->string

MyBatis处理模糊查询

复习:MySql like模糊查询使用详解

  1. %:表示任意个或多个字符。可匹配任意类型和长度的字符 like:%三% 三% %三

  2. _ :表示任意单个字符。匹配单个任意字符,它常用来限制表达式的字符长度语句:_ 可以代表一个中文字符 三_ _三_

在mysql中sql的模式缺省是忽略大小写的

三种方式:
  • select * from t_user where username like %${username}%
  • select * from t_user where username like "%"#{username}"%"
  • select * from t_user where username like concat('%',#{username},'%')

MyBatis处理批量删除

delete * from t_user where id in ({ids}) #{}会自动加单引号,会导致格式不正确 <font color=red>注意不能用#{} 只能用{}

MyBatis处理动态设置表名

sql表名是不能加‘’的 所以只能用${}

select * from ${tablename} ...

添加功能获取自增的主键

useGeneratedKeys:设置当前标签中的sql使用了自增的主键 keyProperty:将自增的主键的值赋值给传输到映射文件中参数的某个属性

<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    insert into t_user values(null,#{username},#{password},#{age},#{sex},#{email})
</insert>

解决字段名和属性名不一致

  1. 为字段起别名,来保持和属性名一致
  2. 设置MyBatis的全局配置,将_自动映射为驼峰
<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
<settings >
<resultMap id="empResultMap" type="Emp">
    <id property="eid" column="eid"></id>
    <result property="empName" column="emp_name"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
    <result property="email" column="email"></result>
</resultMap>

id专门设置主键的映射关系,result设置普通字段映射关系 resultMap: 设置自定义映射关系 id: 唯一标识,不能重复 type: 设置映射关系中的实体类型

子标签: id:设置主键的映射关系 result:设置普通字段的映射关系 属性: property:设置映射关系的属性名,必须是type属性所设置的实体类类型中的属性名 column:设置映射关系中的字段名,必须是sql语句查询出的字段名

通过级联属性赋值解决多对一的映射

  1. 级联属性赋值

  2. association:处理多对一的映射关系 property:需要处理多对的映射关系的属性名 javaType:该属性的类型

  3. 分步查询 select:设置分步查询的sql的唯一表示(namespace.SQLid或mapper接口的全类名 column:设置分步查询的条件 property:分步查询出来的类型

image.png

延迟加载

分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息 lazyLoadingEnable:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载 aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载

fetchType: 当开启了全局的延迟记载以后,可通过此属性手动控制延迟加载的效果 fetchType=“lazy”/“eager”:lazy表示延迟加载,eager表示立即加载

一对多关系

image.png

image.png

处理一对多的映射关系:

  1. collection
    1. collection:处理一对多的映射关系
    2. ofType:表示改属性所对应的集合中存储数据的类型
  2. 分步查询

动态SQL

MyBatis框架的动态SQL技术时一种根据特定条件动态拼装SQL语句的功能。它存在的意义是为了解决拼接SQL语句字符串的痛点问题。

动态SQL: 1. if:根据标签中test属性所对应的表达式决定标签中的内容是否需要拼接到SQL中 2. where:当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and或or,当where标签中没有内容时,此时where标签没有任何效果 注意:where标签不能将其中内容后面多余的and或or去掉 3. trim 若标签中有内容时: prefix|suffix:将trim标签中内容前面或后面添加指定内容 suffixoverrides|prefixoverrides:将trim标签中内容前面或后面去掉指定内容 若标签中没有内容时,trim标签也没有任何效果 image.png 4. choose、when、otherwise,相当于if...else if...else when至少要有一个,otherwise最多只能有一个

image.png 5. foreach: collection:设置需要循环的数组或集合 item:表示数组或集合中的每一个数据 separator:循环体之间的分隔符 open:foreach标签所循环的所有内容的开始符 close:foreach标签所循环的所有内容的结束符

批量删除: image.png

image.png

批量添加:

  • 记得在接口emps参数前加@Param("emps") 否则无法通过emps访问到这个集合 image.png 6. sql标签 设置sql片段: eid,emp_name,age,sex,email 引用sql片段:

MyBatis缓存

一级缓存默认开启

**SqlSession级别 **

一级缓存失效的四种情况:

  • 不同的SqlSession对应不同的一级缓存
  • 同一个SqlSession但是查询条件不同
  • 同一个SqlSession两次查询期间执行了任何一次增删改操作(任何的增删改操作都会直接清空缓存)
  • 在两次查询之间手动清空了缓存
MyBatis的二级缓存

**SqlSessionFactory级别 ** 二级缓存开启的条件:

  1. 在核心配置文件中,设置全局配置属性CacheEnabled=“true”,默认为true,不需要设置
  2. 在映射文件中设置标签 image.png
  3. 二级缓存必须在SqlSession关闭或提交之后有效
  4. 查询的数据所转换的实体类类型必须实现序列化的接口

二级缓存失效的情况: 任何增删改查都会清空一级和二级缓存 Cache Hit Ratio缓存命中率

二级缓存相关配置

  • eviction属性:缓存回收策略
    1. LRU(Least Recently Used) -最近最少使用的
    2. FIFO(First in First Out)
    3. SOFT -软引用:移除基于垃圾回收器状态和软引用规则的对象
    4. WEAK -弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象 默认的是LRU
  • flushInterval属性:刷新间隔,单位毫秒 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句(增删改)时刷新
  • size属性:引用数目,正整数 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
  • readOnly属性:只读 true/false
  • true:只读缓存:会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
  • false:读写缓存:会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

MyBatis缓存查询的顺序

  • 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
  • 如果二级缓存没有命中,在查询一级缓存
  • 如果一级缓存也没有命中,则查询数据库
  • SqlSession关闭之后,一级缓存的数据会写入二级缓存

整合第三方缓存EHCache

MyBatis提供了缓存接口,可以用第三方缓存来替代二级缓存(一级缓存是没办法替代的)

  1. 添加依赖

image.png 2. 各jar包功能

image.png

  1. 创建EHCache的配置文件ehcache.xml

  2. 设置二级缓存的类型

  3. 加入logback日志配置文件

MyBatis的逆向工程

  • 正向工程:先创建Java实体类,由框架负责根据实体类生成数据库,Hibernate是支持正向工程的
  • 逆向工程:先创建数据库,由框架负责根据数据库表,反向生成如下资源
    • Java实体类
    • Mapper接口
    • Mapper映射文件
  1. 创建逆向工程的步骤
  2. 创建MyBatis核心配置文件
  3. 创建逆向工程
    • 文件名必须是:generatorConfig.xml

分页插件

  1. 分页插件使用步骤 a> 添加依赖 image.png b> 配置分页插件 在MyBatis的核心配置文件中配置插件
<plugins>
    <!--设置分页插件-->
    <plugin interceptor="com.github.pagehelper.PageIntegerceptor"></plugin>
</plugins>

分页相关的内容: limit index,pageSize index:当前页的起始索引 pageSize:每页显示的条数 pageNum:当前页的页码 index=(pageSize*(pageNum-1)

使用MyBatis的分页插件实现分页功能:

  1. 需要在查询功能之前开启分页 pageHelper.startPage(int PageNum,int pageSize);

  2. 在查询功能之后获取分页相关信息 pageInfo page=new pageInfo<>(list,5); list表示分页数据 5表示当前导航分页的数量 navigatePageNums: 导航栏一共有的页面数字的个数