MyBatis 从浅入深 随笔整理

时间:2022-09-02 12:36:15

MyBatis?

archetypeCatalog = internal

MyBatis 从浅入深 随笔整理

本文档单独出现的_parameter都标识为变量名

一.三个基本要素:

核心接口和类

MyBatis 核心配置文件

SQL映射文件

二.核心接口和类:

结构图:

MyBatis 从浅入深 随笔整理

(1)每个MyBatis的哟ing有都以一个SqlSessionFactory对象的实例为核心

(2)首先获取SqlSessionFactoryBuilder对象,可以根据XML配置文件或Configuration类的实例构建该对象

(3)然后获取SqlSessionFactory对象,该对象实例可以通过SqlSessionFactoryBuilder对象来获得

(4)有了SqlSessionFactory对象之后,就可以进而获取SqlSession实例,SqlSession对象中完全包含以数据库为背景的所有执行SQL操作方法。可以用该实例来直接执行已映射的SQL语句

1. SqlSessionFactoryBuilder

作用:

构建SqlSessionFactory

Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sfb = new SqlSessionFactoryBuilder().build(reader);

特点:

用过即丢

声明周期和作用域:

SqlSessionFactoryBuilder是利用XML或者Java编码获得资源来购进啊SqlSessionFactory的,通过它可以构建多个SessionFactory。它的作用就是一个构建器,一旦我们构建了SqlSessionFactory,它的作用就已经完结,失去了存在的意义,这时我们就应该毫不犹豫的废弃它,将它回收。所有它的生命周期只存在与方法的局部,它的作用就是生成SqlSessionFactory对象

2. SqlSessionFactory

作用:

创建SqlSession实例

SqlSession sqlSession = sfb.openSession();

生命周期和作用域

SqlSessionFactory对象一旦创建,就会在整个应用过程中始终存在。没有理由去销毁或再创建它,并且应用运行中也不建议多次创建实例,因此,最佳作用域是Application

创建SqlSessionFactory实例时一般放在静态代码块中

 

而,最佳方案是使用依赖注入---Spring框架来管理SqlSessionFactory的单例生命周期

3. SqlSession

作用:

是用于执行持久化操作的对象,类似于JDBC终端Connection。提供了面向数据库执行SQL命令所需的所有方法,可以通过SqlSession实例直接运行已映射的SQL语句

MyBatis 从浅入深 随笔整理

生命周期和作用域:

一个SqlSession对象对应着一次会话。非永久,用完即关,及时释放资源(close()方法)

线程方面:

每个线程都有自己的SqlSession实例,SqlSession实例不能被共享,也不是线程安全的。因此最佳的作用域范围是request作用域或者方法体作用域

两种使用方式:

1. 通过SqlSession实例来直接执行已映射的SQL语句

(1) 添加xx.xml 文件 SQL映射节点

(2) 根据需求利用SqlSession实例直接点出需要使用的方法,(方法传参SQL映射节点的id值)

2. 基于mapper接口方式操作数据

(1) 添加xx.xml 文件 操作SQL节点

(2) 创建绑定映射语句的接口xxx.java 并提供---> 和SQL映射节点id值相同的接口方法

(3) 利用SqlSession实例调用getMapper()方法 ,传参为接口名.class   然后点出相应接口方法

注意:SqlSession实例用完即关

三.核心配置文件:

Mybatis-config.xml

文档结构:

注意先后顺序!!!

Configuration 配置 (根节点)

  Properties 可以配置在Java属性配置文件中

  Settings 修改MyBatis在运行时的行为方式

  TypeAliases 为Java类型命名一个别名

  TypeHandlers 类型处理器

  ObjectFactory 对象工厂

  Plugins 插件

  Environments 环境

  Environment 环境变量

    transactionManager 事物处理器

    dataSource 数据源

  Mappers 映射器

1. configuration元素:

整个xml文件的根节点,相当于MyBatis的总管,所有配置信息都会存放在它里面,MyBatis还提供了设置这些配置信息的方法:

(1) 可以从配置文件李获取属性值

(2) 通过程序直接设置

2. Properties元素:

其描述都是外部化,可替代的属性

属性获取方式:

1. 引入外部properties文件
<properties resource=”数据源路径” />

引入外部文件后,在本xml文件中可直接使用${key值}来获取对应的value值

2. 内部配置 --->元素中直接配置property属性
<properties>
<property name=”key值” value=”value值” />
......
</properties>

配置节点完成后,在本xml文件中可直接使用${key值}来获取对应的value值

3. 内外部结合使用
<properties resource=”外部数据源路径”>
<property name=”key值” value=”value值” />
......
</properties>

配置节点完成后,在本xml文件中可直接使用${key值}来获取对应的value值

如果外部配置和内部配置   配置了相同的key  那么:resource属性值的优先级高于property子节点配置的值

3. Settings元素

作用是设置一些非常重要的设置选项,用于设置和改变MyBatis运行中的行为

设置项

描述

允许值

默认值

cacheEnabled

对在此配置文件下的所有cache进行全局性开/关设置

True|false

True

lazyLoadingEnabled

全局性设置懒加载。如果设为false,则所有相关联的都会被初始化加载

True|false

True

autoMappingBehavior

MyBatis对于resultMap自动映射的匹配级别

NONE|PARTIAL|FULL

PARTIAL

Settings标签配置的是配置MyBatis框架运行时的一些行为,例如:

(1)缓存

(2)延迟加载

(3)结果集控制

(4)执行器

(5)分页设置

(6)命名规则

等一系列控制性参数,其所有的settings配置都放在父标签settings标签中

4. typeAliases元素

作用是配置类型别名,通过与MyBatis的SQL映射文件相关联,减少输入多余的完整类名

两种方式:

1. 直接指定到类
<typeAliases>
<typeAlias alias=”别名” type=”类的全路径” />
......
</typeAliases>

弊端:

如果一个项目有多个POJO的时候需要一一配置

2. 指定包,检索类

解决上面直接指定到类的弊端

通过package的name属性直接指定包名,MyBatis会自动扫描指定包下的JavaBean,并默认设置一个别民,默认名称为JavaBean的非限定类名

<typeAliases>
<typeAlias alias=”别名” type=”某包的全路径” />
</typeAliases>

Xx.xml配置:

直接写包下的某个类名即可

另外:

对于基础数据类型等,Mybatis已经为许多常见的Java类型内建了相应的类型别名,一般都是与其映射类型一致,并且它们都是大小写不敏感的

5. Environments元素:

MyBatis可以配置多套运行环境,如:

(1)开发环境

(2)测试环境

(3)生成环境

等,我们可以灵活选择不同的配置,从而将SQL映射应用到不同的数据库环境上。

这些不同的运行环境,就可以听过environments元素来配置,但是不管增加几套运行环境,都必须要明确选择出当前的唯一一个运行环境。

Because:

每个数据库都是对应一个SqlSessonFactory实例,需要指明哪个运行环境将被创建,并把运行环境中设置的参数传递给SqlSessionFactoryBuilder。

<environments default="development">
<!-- 开发环境 -->
<environment id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
<!-- 测试环境 -->
<environment id="test">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>

几个关键点:

(1)默认的运行ID

通过environments节点的default属性来指定当前的运行环境ID,对于子节点environment环境ID的命名要确保唯一性

(2)TransactionManager事物管理器

设置其类型为JDBC(MyBatis有两种事物管理类型,即JDBC,MANAGED),直接使用JDBC的提交和回滚功能,依赖于数据源获得连接来管理事物的声明周期

(3)配置数据库连接对象

DataSource元素使用标准的JDBC数据源接口来配置JDBC连接对象的资源。

MyBatis提供了三种数据源类型

(1)UNPOOLED

(2)POOLED

(3)JNDI

一般使用POOLED数据源类型。该类型的实现利用“池”的概念将JDBC连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间,是MyBatis实现的简单的数据库连接池类型,它使数据库的连接可被复用,不必在每次请求时都去创建一个物理连接

对于高并发的Web应用是一种流行的处理方式,有利于快速响应请求

6. Mappers元素:

映射器,用来定义SQL的映射语句,我们只需要告诉MyBatis去哪里找到这些SQL语句即可,即去哪里找相应的SQL映射文件(可以使用类资源或者URL资源等方式)

仅只是找到指定映射文件,其更详细的信息配置在每个SQL映射文件中

常用的两种映射方式:

1. 使用类资源路径获取路径
<mappers>
<mapper resource="本项目中SQL映射文件 资源路径"/>
</mappers>
2. 使用URL获取资源
<mappers>
<mapper url="本地或者网络上的SQL映射文件 资源路径"/>
</mappers>

四.DTD文件的引入:

用IDEA 不需要手动引入DTD文件   略略略!!!

五.SQL映射文件:

MyBatis强大之处:SQL映射语句    魅力所在 非常简单

使用SQL映射文件配置可减少50%以上的代码量

MyBatis专注于SQL 极大限度地进行SQL调优,保证性能

MyBatis 从浅入深 随笔整理

几个*元素配置:

1. mapper:

映射文件的根元素节点,只有一个属性namespace(命名空间)

namespace作用:

1. 区分不同的mapper,全局唯一

2. 保定DAO接口,即面向接口。

① 当namespace绑定一个接口后,可以不用写该接口的实现类,MyBatis会通过接口的完整限定名查找到对应的mapper配置来执行SQL语句。因此namespace的命名必须要跟接口同名(包结构+接口名)

namespace命名要求:

1. 命名必须跟某个DAO接口命名,同属于DAO层,故代码结构上,映射文件与该DAO接口放置在同一package下,如果不放在同一package下,需指定其对应接口的资源路径,,接口命名,配置文件命名习惯上以Mapper结尾

2. 在不同的mapper文件中,子元素的id可以相同,MyBatis通过namespace和子元素的id进行联合区分。接口中的方法与映射文件中SQL语句id应一一对应

2. chche:

配置给定命名空间的缓存

3. cache-ref:

从其他命名空间引用的缓存配置

4. resultMap:

用来描述数据库结果集和对象的对应关系

5. Sql:

    通过sql片段达到代码重复利用

可以重用的SQL块,也可以被其他语句使用

我一般用来封装常用的表字段

如:

<sql id="co">
`SUBWAYNAME`,`STARTSTATION`,`ENDSTATION`,`STATIONNUM`,`STARTIME`,`PRICE`
</sql>

使用时:

在标签内插入语句

<include refid="co"/>

6. Insert

映射插入语句

<insert id="add" parameterType="com.metro.entity.SubwayInfo">
INSERT INTO `subwayInfo`(
<include refid="co"/>
)
VALUES (#{subwayName},#{startStation},#{endStation},#{stationNum},#{starTime},#{price})
</insert>

7. Update:

映射更新语句

<update id="up" parameterType="com.metro.entity.SubwayInfo">
UPDATE `subwayInfo`
<set>
<if test="subwayName!=null and "".equals(subwayName.trim())">SUBWAYNAME=#{subwayName},</if>
<if test="startStation!=null and "".equals(startStation.trim())">STARTSTATION=#{startStation},</if>
</set>
WHERE id=#{id}
</update>

8. Delete:

映射删除语句

<delete id="del" parameterType="INTEGER">
DELETE from subwayInfo where id=#{id}
</delete>

9. Select:

映射查询语句

<select id="listAll" resultMap="subwayInfo">
SELECT id,<include refid="co"/> FROM subwayInfo
</select>

别名与Java类型映射:

别名

映射类型

string

String

byte

Byte

long

Long

short

Short

int

Integer

integer

Integer

arraylist

Arraylist

double

Double

float

Float

boolean

Boolean

date

Date

map

Map

hashmap

HashMap

list

List

SQL映射标签详解:

1. resultMap

映射查询结果,两种方案:

1)使用resultType做自动映射

<!--resultType 大小写不敏感:不需resultMap标签映射,,依靠实体类字段名与数据库相应字段名相同进行映射
  严重受限
 -->

字段名与POJO的属性名必须一致。若不一致,则需要给字段起别名,保证别名与属性名一致

不推荐使用

2)通过resultMap来映射自定义结果

使用resultMap标签做自定义结果映射,字段名可以不一致,并且还可以指定要显示的列,比较灵活,应用广泛

<resultMap type="com.metro.entity.SubwayInfo" id="subwayInfo">
<!--typeHandler="" 可做数据类型转换-->
<!--column="" 数据库字段property=”” 实体类字段-->
<id column="ID" jdbcType="INTEGER" property="id" />
<result column="SUBWAYNAME" jdbcType="VARCHAR" property="subwayName"/>
<result column="STARTSTATION" jdbcType="VARCHAR" property="startStation"/>
<result column="ENDSTATION" jdbcType="VARCHAR" property="endStation"/>
<result column="STATIONNUM" jdbcType="INTEGER" property="stationNum"/>
<result column="STARTIME" jdbcType="VARCHAR" property="starTime"/>
<result column="PRICE" jdbcType="INTEGER" property="price"/>
</resultMap>

jdbcType插入空值时,需要指定jdbcType

Mybatis insert空值报空值异常,但是pl/sql不会提示错误,主要原因是mybayis无法进行转换

各属性标签:

Id:唯一标识,此id用于sql映射元素 resultMap属性的引用

Type:表示该resultMap的映射结果类型

result子节点:用于标识一些简单属性

 

返回类型resultType 与 resultMap?

这里的resultType 与 resultMap跟上面所说的那个不一样,,这里探讨的是Sql映射标签  返回类型

1. resultType:

直接表示返回类型,包括基础数据类型和复杂数据类型

2. resultMap:

对外部resultMap定义的引用,对应外部resultMap的id,表示返回的结果集映射到哪一个resultMap上。应用场景:数据库字段信息与对象属性不一致或者需要做复杂的联合查询以便*控制映射结果

MyBatis 从浅入深 随笔整理

3. resultType和resultMap的关联

无论是resultType还是resultMap,其实查询出来的每个字段值都放在一个对应的Map里面,其键是字段名,值是其对应的值

然后呢,当select元素提供的返回值类型是resultType的时候,MuBatis会将Map里面的键值对取出赋给resultType所指定的对象对应的属性(即调用对应的对象里的属性的setter方法进行填充)

··所以呢,其实每个查询的返回类型都是resultMap

1)只是当我们提供的返回值类型属性是resultType 的时候,会自动把对应的赋值resultType 所指定对象的属性

2)我们提供的返回类型是resultMap的时候,因为Map不能很好的表示领域模型,我们就需要通过进一步的定义把它转化为对应的实体对象

开发经验:

当返回类型是resultMap时,主要用在进行复杂联合查询上

进行简单查询时,使用resultType 足以

注意:在select元素中,resultType 和resultMap本质上是一样的,都是Map数据结构

明确一点。。。两种绝对不能同时存在,只能二者选其一使用

4. resultMap的自动映射级别

resultMap自动映射级别默认的是PARTIAL,为自动装配,他会自动装配所有查询出来并且实体类里拥有的字段

如果想要选择部分字段进行映射,希望没有映射的字段是不能在后台查询并输出的,则需要在核心配置文件settings中设置resultMap的自动映射级别(autoMappingBehavior)为NONE,即禁止自动匹配

<settings>
<setting name="autoMappingBehavior" value="NONE"/>
</settings>

注意点:

在MyBatis中,使用resultMap能够进行自动映射匹配的前提是字段名和属性名需要一致,在默认映射级别(PARTIAL)情况下:

1)若一致,即使没有做属性名和字段名的匹配映射,也可以在后台获取到未匹配过的属性值

2)若不一致,且在resultMap里没有做映射,那么就无法在后台获取并输出

2. Select

属性:
1)Id

命名空间中唯一的标识符,可以被用来引用这条语句

由于我们常用的映射方法是基于Mapper接口,所有id值需跟对应的接口方法名一致

2)ParameterType:

标识查询语句传入参数的类型的完全限定名或别名。

MyBatis 从浅入深 随笔整理

支持继承数据类型和复杂数据类型

MyBatis有内建的类型别名,,上面有!!!

除了内建的类型别名外,还可以为自定义的类设置别名。。。在核心配置文件的typeAliases元素中设置

在映射文件中可直接使用别名,以减少配置文件的代码量

注:

1. 基本情况下只允许传入一个参数,如果要传入多个参数,,就要对多个参数进行封装后续还可以使用@Param注解实现多参数入参

2. Mybatis传入参数类型可以是Java继承数据类型,但是只适用于一个参数的情况,通过#{参数名}即可获取传入的值。若是多参数入参,需要复杂数据类型来支持,包括Java实体类,map,通过#{属性名}或者#{Map的key}来获取传入的参数值

#{值}:写法是OGNL表达式

MyBatis 从浅入深 随笔整理

MyBatis 从浅入深 随笔整理

MyBatis 从浅入深 随笔整理

如果是实体类对象和基本数据类型多参数传参

取值时:实体类对象.属性名

3)ResultType:

查询语句返回结果类型的完全限定名或别名,命名与ParameterType大体一致

3. Insert,Update,Delete

属性:
1)id:

与select元素的id一样,是命名空间中唯一的标识符,可以呗用来引用这条语句

2)ParameterType:

与select元素其属性一样,是传入参数的类型的完全限定名或别名

注意点:

对于增删改(insert,update,delete)这类数据库更新操作

1)该类型的操作本身默认返回执行SQL影响的行数,所以DAO层的接口方法的返回值一般设置为int类型。最好不要返回boolean类型

2)Insert,update,delete元素中均没有resultType属性,只有查询操作需要对返回结果类型(resultType/resultMap)进行相应的指定

3)在测试类中,当sqlSession执行完sql操作之后,需要进行commit,完成数据的插入操作。若在执行的过程中抛了异常,那么就必须在catch中进行回滚,以此来保证数据的一致性,同时设置count为0

六.使用@param注解实现多参数入参

int del(@Param("uid")Integer id,@Param("xxx")String x);

解析:

使用注解@Param来传入多个参数,并且注解内可以将变量名重命名为其他名字,,只会影响SQL映射文件的使用,不会影响java类中的真实使用。。在映射文件中使用#{注解内的值}来获取其传入的值,,,

还有啊,使用注解,装配的入参,参数类型必须是引用类型(复杂类型或String,或者基本数据类型的包装类,对象等)使用int等值值类型,会报错

如果是实体类对象和基本数据类型多参数传参

取值时:

实体类:#{注解内的值.属性名}

基本:#{名}

扩展:

使用多参数入参,必须使用@Param注解方式,若不使用,则会报错,报错信息类似于Pararmeter‘参数名’ not found。

Reason:

深入MyBatis源码,我们可以发现,MyBatis的参数类型为Map

1)若使用@Param注解参数,那么就会记录指定的参数名为key

2)若参数前没有加@Param,那么就会使用“param”+它的序号座位Map的key。

故而进行多参数入参时,若没有使用@Param指定参数key,那么在映射的SQL语句中获取不到#{参数名},从而报错

经验:

相信大家学了@Param注解入参就会有疑惑,既然有高级货,为什么不早拿出来???

其实呢,普通入参方式也不是一无是处,下面我们来谈论一下《在MyBatis中参数入参,何时需要封装成对象入参,何时又需要使用多参数入参???》

来,let’s go  :

1)一般情况下呢,超过4个参数最好封装成对象入参(特别是在常规的增加和修改操作时,字段较多,封装成对象比较方便,也省的一个个记参数名了,也不是)

2)对于参数固定的业务方法呢,最好使用多参数入参,原因是这种方法比较灵活,代码的可读性高,可以清晰地看出接口方法中所需的参数是什么。并且对于固定的接口方法,参数一般是固定的,所以直接多参数入参即可,无需封装对象(比如修改个人密码,根据用户id删除用户,根据用户id查看用户明细,都可以采用这种方式)

需要注意的是:

当参数为基础数据类型时,不管是多参数入参还是单独一个参数,都需要使用@Param注解来进行参数的传递

还有一定记住一点。。使用多参数入参时。在SQL映射文件中使用OGNL表达式获取传开的值的时候 其key值是@Param()括号中的值

七.ResultMap实现高级结果映射

我们先回顾一下前面提到的resultMap的基本配置

基本配置:

1> 属性

1)id:resultMap的唯一标识

2)Type:标识该resultMap的映射结果类型(通常时Java实体类)

2> 字节点

1)id:一般对应数据库中该行的主键id,设置此项可以提升MyBatis性能

2)Result:映射到JavaBean的某个“简单类型”属性,如:基础数据类型,包装类等

子节点id和result均可实现最基本的结果集映射,将列映射到简单数据类型的属性。

这两者唯一不同的是:在比较对象实例时id将作为结果集的标识属性。有助于提高整体性能,特别是应用缓存和潜逃结果映射的时候

高级结果映射,两个配置项:

1> Association

映射到JavaBean的某个“复杂类型”属性,比如JavaBean类,即JavaBean内部嵌套一个复杂数据类型(JavaBean)属性,这种情况就属于复杂类型的关联。

需要注意的是:

Association仅处理一对一的关联关系(比如,每个用户都会有一个角色,两表关系一对一)

<resultMap type="com.metro.entity.User" id="user">
<id column="ID" jdbcType="INTEGER" property="id" />
<result column="NAME" jdbcType="VARCHAR" property="name"/>
<result column="PWD" jdbcType="VARCHAR" property="pwd"/>
<association property="role" javaType="Roel">
<id property="rid" column="RID"/>
<result property="rname" column="RNAME"/>
</association>
</resultMap>
<select id="listAll" resultMap="user" parameterType="Integer">
SELECT u.* r.id AS RID,r.name AS RNAME FROM user u,role r
WHERE u.rid=r.id AND u.id=#{uid}
</select>
分析其属性:
Association元素:

1> javaType:

完整Java类名或者别名。

1)若映射到一个JavaBean,则MyBatis通常会自行检测到其类型;

2)若映射到一个HashMap,则应该明确指定JavaType,来确保所需行为。此处为Role

2> Property:

映射数据库列的实体对象的属性。此处为在User里定义的属性role

其子节点元素:

1> Id:

不多说,看下面

2> Result:

不多说,看下面

上两者共同属性:

1)property:

映射数据库列的实体对象的属性,上面的例子为Role的属性

2)colunm:

数据库对象的列名或别名

注意:

Id子元素在嵌套结果映射中扮演了一个非常重要的角色,应该指定一个或者多个属性来唯一标识这个结果集。实际上,即使没有值得id,MyBatis也会工作,但是会导致严重的性能开销,所以最好选择尽量少的属性来唯一标识结果,主键或者联合主键均可

最后:

了解了关于association的基本用法以及使用场景,一些复用大佬,就会想到这个东东可不可以复用呢,,

答案是肯定的,association提供了另一个属性:resultMap。(相信说到这里大家已经指定怎么做了,每次就是跟select等映射标签一样,,搞呗,resultMap=“某resultMap元素id值”)通过这个属性可以扩展一个resultMap来进行联合映射,这样就可以使其结果映射重复使用。当然,若不需要复用,也可安装之前的写法,直接嵌套这个联合结果映射,根据具体业务而定

<resultMap type="com.metro.entity.User" id="user">
<id column="ID" jdbcType="INTEGER" property="id" />
<result column="NAME" jdbcType="VARCHAR" property="name"/>
<result column="PWD" jdbcType="VARCHAR" property="pwd"/>
<association property="role" javaType="Roel" resultMap="role"/>
</resultMap> <resultMap id="role" type="Role">
<id property="rid" column="RID"/>
<result property="rname" column="RNAME"/>
</resultMap>

引用外部resultMap的好处:可以达到复用的效果,并且整体的结构较为清晰,特别适合association的结果映射比较多的情况

返回对象

Association可以处理一对一的关联关系,那么对于一对多的关联关系的处理,它就心有余而力不足了,,,,,怎么办呢?嗯,用collection元素

2> Collection

作用和association元素的作用差不多一样,事实上,它们非常类似,也是映射到JavaBean的某个“复杂类型”属性,只不过这个属性是一个集合列表,即JavaBean内部嵌套一个复杂数据类型(集合)属性。和使用association元素一样,我们使用嵌套查询,或者从连接中嵌套结果集

<resultMap id="role" type="Role">
<id property="rid" column="RID"/>
<result property="rname" column="RNAME"/>
<collection property="juris" ofType="Juris" resultMap="ju"/>
</resultMap>
<resultMap id="ju" type="Juris">
<id property="jid" column="JID"/>
<result property="jname" column="JNAME"/>
</resultMap>

与association用法基本一致,就是多出来了一个ofType属性

ofType属性呢:代表的是Java类名或者别名,即集合所包含的类型

返回集合

八.ResultMap自动映射级别和MyBatis缓存

(一)resultMap自动映射级别

resultMap自动映射的三个匹配级别:

1> NONE:

禁止自动匹配

2> PARTIAL:

默认自动映射级别,自动匹配所以属性,有内部嵌套的(association、collection)的除外

3> FULL:

自动匹配所有,所有所有!!!

详解:

用法:

在核心配置中配置:

<settings>
<setting name="autoMappingBehavior" value="匹配级别"/>
</settings>

NONE禁止自动匹配不用多说,就是不自动匹配嘛,手动映射啥就匹配啥并且赋值,否则没值,并且上面也举过例子,所有不再做过多阐述

主要讲解PARTIAL与FULL的区别

可以私下里做个例子,发现没有设置autoMappingBehavior的时候,也就是默认情况下(PARTIAL),若是普通数据类型的属性,会自动匹配所有,,,,,但是呢若是内部嵌套(association或collection)(集合或实体对象),那么输出结果就是null。也就是说它不会自动匹配,除非手工设置autoMappingBehavior的value为FULL(自动匹配所有)

修改后你会发现autoMappingBehavior的value为FULL(自动匹配所有)之后,未作映射的字段(任何类型)均有值输出

(二)MyBatis缓存

如大多数持久化框架一样,MyBatis提供了一级缓存和二级缓存的支持

一级缓存缓存的是SQL语句,二级缓存缓存的是结果对象

1. 一级缓存

一级缓存是基于PerpetualCache(MyBatis自带)的HashMap本地缓存,作用范围为session域内,当session flush或者close之后,该session中所有的cache就会清空

配置:

因为MyBatis默认就是一级缓存,所以删除所有关于缓存的配置,就是一级缓存

2. 二级缓存

二级缓存就是global caching,它超出session范围之外,可以被所有的SqlSession共享,开启它只需要在MyBatis的核心文件settings中设置即可

三种配置方法:

为cache赋值:true为二级缓存。false为一级缓存

1)MyBatis的全局cache配置

在核心文件配置:

<settings>
<setting name="cacheEnabled" value="false"/>
</settings>
2)针对mapper的namespace

1)在mapper文件(也就是SQL映射文件)中设置缓存,默认情况下是没有开启缓存

2)需要注意的是,global caching发作用域是针对mapper的namespace而言的,即只有namespace内的查询才能共享这个cache

<mapper namespace="SubwayInfo">
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
。。。。
</mapper>

代表创建了一个LRU缓存,并每隔60秒刷新,最大存储512个对象,而且返回的对象被认为是只读的。

evicition收回策略,默认是LRU

(1)LRU最近最少使用策略,一处做长时间不被使用的对象。

(2)FIFO先进先出策略,按对象进入缓存的顺序来移除它们。

(3)SOFT软引用策略,移除基于垃圾回收器状态和软引用规则的对象。

(4)WEAK弱引用策略,更积极地移除基于垃圾收集器状态和弱引用规则的对象。

3)针对个别查询进行调整

配置这个的前提是必须配置好上面2)针对mapper的namespace

如果需要对个别查询进行调整,可以单独设置cache:

<select id="listAll" resultMap="subwayInfo" useCache="true">
。。。
</select>

详解一二级缓存的区别:

一级缓存基于sqlSession默认开启,在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap用于存储缓存数据。不同的SqlSession之间的缓存数据区域是互相不影响的。

一级缓存的作用域是SqlSession范围的,当在同一个sqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存),

第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。

需要注意的是,如果SqlSession执行了DML操作(增删改),并且提交到数据库,MyBatis则会清空SqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息,避免出现脏读现象。

当一个SqlSession结束后该SqlSession中的一级缓存也就不存在了。

关闭一级缓存后,再次访问,需要再次获取一级缓存,然后才能查找数据,否则会抛出异常。
二级缓存是mapper级别的缓存。使用二级缓存时,多个SqlSession使用同一个Mapper的sql语句去操作数据库,得到的数据会存在二级缓存区域,它同样是使用HashMap进行数据存储。相比一级缓存SqlSession,二级缓存的范围更大,多个Sqlsession可以共用二级缓存,二级缓存是跨SqlSession的。

二级缓存的作用域是mapper的同一个namespace。不同的sqlSession两次执行相同的namespace下的sql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数据写到缓存,第二次查询会从缓存中获取数据,不再去底层数据库查询,从而提高效率。

最后:

对于MyBatis缓存的内容仅做了解即可,因为面对一定的数据量,内置的Cache方式就派不上用场了

并且对查询结果集做缓存并不是MyBatis框架擅长的,它专心做的应该是SQL映射,所有我们一般采用 OSCache、Memcached等专门的缓存服务器来做更为合理

九.动态SQL咯

很简单。。也就是标签元素,,没什么技术含量

记住拿过来用就好、

各标签元素

为了支持用户多样化操作

1. If

<if test="subwayName!=null and "".equals(subwayName.trim())">AND SUBWAYNAME=#{subwayName}</if>

 

"" 代表空字符串   某些原因,“”不可用

 

test内 的返回结果为true走标签内部结构

否则不进,注意,这里面没有else标签,要想实现if-else结构标签,后面有新引入的标签,这里不做详细讲解,请继续去阅读

2. Where

可以智能 的处理where和and所处的位置

因为我们要动态拼接,where语法:where xxx=x and yyy=y

有时呢,我们拼接sql的时候where子句不好拼接,因为我们确定不了到底哪里是第一个条件的开头,where到底拼接到哪个语句前面,,所以就诞生了这个where标签:

<select id="listAll" resultMap="subwayInfo" >
SELECT id,<include refid="co"/> FROM subwayInfo <where>
<if test="subwayName!=null and "".equals(subwayName.trim())">AND SUBWAYNAME=#{subwayName}</if>
<if test="startStation!=null and "".equals(startStation.trim())">AND STARTSTATION=#{startStation},</if> </where>
</select>

在这里我们会发现sql因为有两个if条件不清楚到底会符合一条还是两条,或者说都不符合,where将要放的位置会异常尴尬

然后呢,可有看到我们这个例子的sql我并没有写where   为什么呢?因为无论执行的怎样我们的where都会为什么自动在最前面拼上where 子句,,如果呢,后面标签内都不符合那么where 不会拼接

做的很牛逼!!!

3. Choose

这里,,,choose,就是上面所说的可以实现if-else结构的标签,,没有久等吧,嘿嘿嘿

Choose标签呢,他又有两个子标签来配合他实现结构功能分别是:

When

  If语句或者else if 语句

Otherwise

  Else语句

<choose>
<when test="">xx</when>
<when test="">yy</when>
<otherwise>zz</otherwise>
</choose>

比如上面的语句

最后只会出现一个值,   xx或者yy或者zz

第一个when就充当了if()

第二个when就充当了else if()

就算后面更多when也充当的是else if()语句  (test为true输出,但when只会执行一道,靠前者优先)

有人疑惑了,那最后的else呢?

Ok ,,,当然是之前没有出场的otherwise标签了,(所以条件不满足的时候走)

学过选择结构,不傻  的相信都 一点就懂,不多说

4. Set

Set元素主要用于更新操作,它的主要功能和where元素差不多,主要在包含的语句前输出宇哥set,若包含的语句是以逗号结束的,会自动把改逗号忽略掉,再配合id元素就可以动态地更新需要修改的字段;而不需修改的字段,则可以不再更新(因为有的时候在update操作中使用多个if或者别的选择标签,若一部分没有执行,则导致在语句末尾残留多余的逗号,解决此问题)

Tip:

<update id="up" parameterType="com.metro.entity.SubwayInfo">
UPDATE `subwayInfo`
<set>
<if test="subwayName!=null and "".equals(subwayName.trim())">
SUBWAYNAME=#{subwayName},
</if>
<if test="startStation!=null and "".equals(startStation.trim())">
STARTSTATION=#{startStation},
</if>
</set>
WHERE id=#{id}
</update>

5. Trim

更为灵活的元素,,,可以替代之前的

Trim元素也会自动识别其标签内是否有返回值,若有返回值,会在自己包含的内容前加上某些前缀(prefix),也可在其后加上某些后缀(suffix),也可把包含内容的首部某些内存覆盖(忽略)(prefixOverrides),或者把尾部的某些内容覆盖(suffixOverrides),无可厚非的强大,可以利用trim替代where或者set元素,实现相同效果

小Tip:

<trim prefix="where" prefixOverrides="and | or">
<if Test=””> and xx = x </if>
。。。
</trim>

不会报错,,前面的and会自动消除,,贼智能,,后缀处理同理

再解释一个各属性:

1> Prefix:

前缀,作用是通过自动识别是否有返回值后,在trim包含的内容上加上前缀,一般用于where

2> Suffix:

后缀,作用是在trim包含的内容上加上后缀

3> prefixOverrides:

对于trim包含内容的首部进行指定内容(如where子句中的and和or)的忽略。

4> suffixOverrides:

对于trim包含内容的首尾部进行指定内容的忽略。

6. Foreach

当MyBatis入参为数组类型的时候,就需要使用foeach来进行迭代取值了

Foreach呢,主要用于构建in条件中,他可以在sql语句中迭代一个集合,,主要属性有:

1)Item:

表示集合中每个元素进行迭代时的别名

2)Index:

指定一个名称,用于表示在迭代过程中,每次迭代到的位置

3)Close:

表示该语句以什么结束(这里以in条件语句举例,,所以用“)”结束,具体根据需求而定)

4)Open:

表示该语句以什么开始(这里以in条件语句举例,,所以用“(”开始,具体根据需求而定)

5)Separator

表示在每次进行迭代之间以什么符号作为分隔符(这里以in条件语句举例,,,所以用“,”分隔)

6)Collection:

最关键并最容易出错的属性,需要格外注意,改属性必须指定 不同情况下,该属性的值是不一样的。注意有三种情况:

a. 若入参为单参数且参数类型是一个List的时候,collection的属性值为list

b. 若从入参为单参数且参数类型是一个数组的时候,collection属性值为array

c. 若传入参数为多参数,就需要把它们封装为一个Map进行处理

最后来个关于collection三种情况的例子吧:

1.单参数List的类型:

<select id="dynamicForeachTest" parameterType="java.util.List" resultType="Blog">            select * from t_blog where id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>

上述collection的值为list,对应的Mapper是这样的

public List dynamicForeachTest(List ids); 

测试代码:

      @Test
public void dynamicForeachTest() {
SqlSession session = Util.getSqlSessionFactory().openSession();
BlogMapper blogMapper = session.getMapper(BlogMapper.class);
List ids = new ArrayList();
ids.add(1);
ids.add(3);
ids.add(6);
List blogs = blogMapper.dynamicForeachTest(ids);
for (Blog blog : blogs)
System.out.println(blog);
session.close();
}

2.单参数array数组的类型:

<select id="dynamicForeach2Test" parameterType="java.util.ArrayList" resultType="Blog">
select * from t_blog where id in
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>

上述collection为array,对应的Mapper代码:

public List dynamicForeach2Test(int[] ids); 

对应的测试代码:

  @Test
public void dynamicForeach2Test() {
SqlSession session = Util.getSqlSessionFactory().openSession();
BlogMapper blogMapper = session.getMapper(BlogMapper.class);
int[] ids = new int[] {1,3,6,9};
List blogs = blogMapper.dynamicForeach2Test(ids);
for (Blog blog : blogs)
System.out.println(blog);
session.close();
}

3.自己把参数封装成Map的类型

 <select id="dynamicForeach3Test" parameterType="java.util.HashMap" resultType="Blog">          select * from t_blog where title like "%"#{title}"%" and id in
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>

上述collection的值为ids,是传入的参数Map的key,对应的Mapper代码:

public List dynamicForeach3Test(Map params); 

对应测试代码:

@Test
public void dynamicForeach3Test() {
SqlSession session = Util.getSqlSessionFactory().openSession();
BlogMapper blogMapper = session.getMapper(BlogMapper.class);
final List ids = new ArrayList();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(6);
ids.add(7);
ids.add(9);
Map params = new HashMap();
params.put("ids", ids);
params.put("title", "中国");
List blogs = blogMapper.dynamicForeach3Test(params);
for (Blog blog : blogs)
System.out.println(blog);
session.close();
}

7. Include

最后提一句这个标签。。。怕忘了,,用于引用外部sql标签

未完,待续。。。

MyBatis 从浅入深 随笔整理的更多相关文章

  1. Mybatis源码解析,一步一步从浅入深(一):创建准备工程

    Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...

  2. Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码

    在文章:Mybatis源码解析,一步一步从浅入深(一):创建准备工程,中我们为了解析mybatis源码创建了一个mybatis的简单工程(源码已上传github,链接在文章末尾),并实现了一个查询功能 ...

  3. Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)

    在上一篇文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码 ,中我们看到 代码:XMLConfigBuilder parser = new XMLConfigBuilder(read ...

  4. Mybatis源码解析,一步一步从浅入深(四):将configuration&period;xml的解析到Configuration对象实例

    在Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们看到了XMLConfigBuilder(xml配置解析器)的实例化.而且这个实例化过程在文章:Mybatis源码解析,一步一步从浅 ...

  5. Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析

    在上一篇文章Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例中我们谈到了properties,settings,envir ...

  6. Mybatis源码解析,一步一步从浅入深(六):映射代理类的获取

    在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们提到了两个问题: 1,为什么在以前的代码流程中从来没有addMapper,而这里却有getMapper? 2,UserDao ...

  7. Mybatis源码解析,一步一步从浅入深(七):执行查询

    一,前言 我们在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码的最后一步说到执行查询的关键代码: result = sqlSession.selectOne(command.ge ...

  8. 浅入深出Vue:代码整洁之封装

    深入浅出vue系列文章已经更新过半了,在入门篇中我们实践了一个小小的项目. <代码整洁之道>一书中提到过一句话: 神在细节中 这句话来自20世纪中期注明现代建筑大师 路德维希·密斯·范·德 ...

  9. 浅入深出之Java集合框架(上)

    Java中的集合框架(上) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架 ...

随机推荐

  1. 有了门面,程序会更加体面!- pos软件基于三层架构 -09

    续上篇)        大鸟说道:“实际上没有学过设计模式去理解三层架构会有失偏颇的,毕竟分层是更高一级别的模式,所谓的架构模式.不过在程序中,有意识的遵循设计原则,却也可以有效的做出好的设计.”   ...

  2. 斯坦福第十四课:降维&lpar;Dimensionality Reduction&rpar;

    14.1  动机一:数据压缩 14.2  动机二:数据可视化 14.3  主成分分析问题 14.4  主成分分析算法 14.5  选择主成分的数量 14.6  重建的压缩表示 14.7  主成分分析法 ...

  3. hdu 1039 Easier Done Than Said&quest; 字符串

    Easier Done Than Said?                                                                     Time Limi ...

  4. 如何删除MyEclipse(eclipse)中不需要的workspace

    在安装目录下,打开eclipse/configuration/.settings,用记事本打开org.eclipse.ui.ide.prefs文件 #Wed Mar 11 14:41:21 CST 2 ...

  5. poj 2689 大范围内素数筛选

    /** 给定一定范围求其内的素数 注意: **/ #include <iostream> #include <math.h> #include <cstring> ...

  6. 可视化:svg相关基础

    01.svg的嵌入.html <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  7. EF Core利用Scaffold从根据数据库生成代码

    在EF6 之前的时代,如果需要从数据库中生成代码,是可以直接在界面上操作的,而到了EF Core的时代,操作方式又有更简便的方式了,我们只需要记住以下这条指令. Scaffold-DbContext ...

  8. mysql字符集设置注意事项

    mysql字符集设置必须是在具体的某一个数据库情况下才能进行设置 否则会报错.

  9. java io系列11之 FilterOutputStream

    FilterOutputStream 介绍 FilterOutputStream 的作用是用来“封装其它的输出流,并为它们提供额外的功能”.它主要包括BufferedOutputStream, Dat ...

  10. 大数据技术之&lowbar;19&lowbar;Spark学习&lowbar;04&lowbar;Spark Streaming 应用解析 &plus; Spark Streaming 概述、运行、解析 &plus; DStream 的输入、转换、输出 &plus; 优化

    第1章 Spark Streaming 概述1.1 什么是 Spark Streaming1.2 为什么要学习 Spark Streaming1.3 Spark 与 Storm 的对比第2章 运行 S ...