[SSM][5][映射器]
第5章 映射器
映射器由一个接口加上 XML
文件(或者注解)组成。在映射器中可以配置参数、各类的SQL
语句、存储过程、缓存、级联等复杂的内容,并且通过简易的映射规则映射到指定的POJO
或者其他对象上,映射器能有效消除JDBC
底层的代码。
MyBatis
的映射器也可以使用注解完成,但是应用不广,原因主要来自3个方面
- 面对复杂性,
SQL
会显得无力,尤其是长SQL
- 注解的可读性较差
- 在功能上,注解丢失了XML 上下文相互引用的功能
5.1 概述
映射器的配备元素如下
元素名称 | 描述 | 备注 |
---|---|---|
select | 查询语句 | 可以自定义参数,返回结果集等 |
insert | 插入语句 | 执行后返回一个整数,代表插入的条数 |
update | 更新语句 | 执行后返回一个整数,代表删除的条数 |
sql | 允许定义一部分SQL,然后在其他地方引用它 | 例如,一张表列名,一次定义,可以在多个SQL语句中使用 |
resultMap | 用来描述从数据库结果集中来加载对象 | 它将提供映射规则 |
cache | 给定命名空间的缓存配置 | 无 |
cache-ref | 其他命名空间缓存配置的引用 | 无 |
5.2 select元素(查询语句)
5.2.1 简单的select元素的应用
先学习一个简单的例子: 统计用户表中同一个姓氏的用户数量
|
|
然后解释这个例子
id
配合Mapper
的全限定名,联合成为一个唯一的标识符,标识这条SQL
parameterType
表示这条SQL
接受的参数类型,可以是MyBatis
系统定义或自定义的别名,也可以是类的全限定名resultType
表示这条SQL
返回的结果类型#{firstName}
是被传递进去的参数
5.2.2 自动映射和驼峰映射
MyBatis
提供了自动映射功能,在默认情况下自动映射功能是开启的,使用它的好处是能有效减少大量的映射配置,从而减少工作量
在setting
元素中有两个可以配置的选项autoMappingBehavior
和mapUnderscoreToCamelCase
,它们是控制自动映射和驼峰映射的开关
举个简单的例子来说明自动映射和驼峰映射
首先给出一个简单的POJO
,Role
|
|
下面通过自动映射完成需求: 通过角色编号获取角色的信息
|
|
- 这里原来的列名
role_name
被别名roleName
代替,这样就和POJO
上的属性名称保持一致了
如果系统都严格按照驼峰命名法,(例如,数据库字段role_name
,对应POJO
属性名为roleName
),此时可以改写为
|
|
自动映射和驼峰映射都建立在SQL列名和POJO属性名的映射关系上,而现实中会更加复杂,此时resultType
元素是无法满足这些需求的。如果需要更为强大的映射规则,则需要考虑使用resultMap
5.2.3 传递多个参数
在现实需求中,经常需要传递多个参数。传参方法有4种
5.2.3.1 使用map接口传递多个参数
可以使用Map
接口通过键值对传递多个参数,把接口方法定义为
|
|
此时传递给映射器的是一个map
对象,使用它在SQL中设置对应的参数
|
|
5.2.3.2 使用注解传递多个参数
使用map
传递参数的弊病是可读性差,为此MyBatis
为开发者提供了一个注解@Param
,可以通过它去定义映射器的参数名称,使用它可以得到更好的可读性,把接口方法定义为:
|
|
此时映射文件可以定义为,此时并不需要给出parameterType
属性,让MyBatis
自动探索即可
|
|
但是这会带来一个麻烦。如果SQL
很复杂,拥有大于10个参数,那么接口方法的参数个数就多了,使用起来就很不容易
5.2.3.3 通过JavaBean传递多个参数
可以通过传递Java Bean
的方式来处理参数过多的问题
先定义一个参数的POJO
:RoleParams
|
|
把接口方法定义为
|
|
此时映射文件定义为:其中parameterType
设置为上文定义的POJO的路径
|
|
引用JavaBean
定义的属性作为参数,然后查询
|
|
5.2.3.4 混合使用
略
5.2.3.5 总结
- 使用
map
传递参数导致了业务可读性的丧失,导致后续扩展和维护的困难,在实际的应用中要果断废弃这种方式。 - 使用
@Param
注解传递多个参数,受到参数个数(n)的影响。当n<=5
时,这是最佳的传参方式,它比用Java Bean
更好,因为它更加直观;当n>5
时,多个参数将给调用带来困难,此时不推荐使用它。 - 当参数个数多于5个时,建议使用
Java Bean
方式。 - 对于使用混合参数的,要明确参数的合理性。
5.2.4 使用resultMap映射结果集
为了支持复杂的映射,select
元素提供了resultMap
属性,例子如下
|
|
resultMap
元素定义了一个roleMap
,它的属性id
代表它的标识,type
代表使用哪个类作为其映射的类- 子元素
id
代表resultMap
的主键,而result
代表其属性,id
和result
元素的属性property
代表POJO
的属性名称,而column
代表SQL
的列名 - 在
select
元素中的属性resultMap
制定了采用哪个resultMap
作为其映射规则
5.2.5 分页参数RowBounds
MyBatis
支持分页,它还内置了一个专门处理分页的类RowBounds
,使用它十分的简单,只要给接口增加一个RowBounds
参数即可。
|
|
|
|
注意上面代码并没有任何关于RowBounds
参数的消息,它是MyBatis
的一个附加参数,MyBatis
会自动识别它,据此进行分页,测试程序如下
|
|
但是要注意RowBounds
分页运用的场景,它只适用于一些小数据量的查询。RowBounds
分页的原理是执行SQL
的查询后,按照偏移量和限制条数返回查询结果,所以对于大量的数据查询,它的性能并不佳,此时可以通过分页插件去处理,详情可参考本书第8章的内容。
5.3 insert元素(插入语句)
5.3.1 概述
插入数据依赖于insert
语句
5.3.2 简单的insert语句的应用
|
|
id
标识出这条SQL
parameterType
代表传入参数类型
5.3.3 主键回填
大多数场景下,我们会为MySQL
中的表配置自增主键。而有时候我们需要取出新插入元素的自增主键。
JDBC
中的Statement
对象在执行插入的SQL
后,可以通过getGeneratedKeys
方法获得数据库生成的主键(需要数据库驱动支持),这样便能达到获取主键的功能。在insert
语句中有一个开关属性useGeneratedKeys
,用来控制是否打开这个功能,它的默认值为false
。当打开了这个开关,还要配置其属性keyProperty
或keyColumn
,告诉系统把生成的主键放入哪个属性中,
|
|
5.3.4 自定义主键
有时候主键可能依赖于某些规则,比如取消角色表(t_role)的id
的递增规则,而将其规则修改为:
- 当角色表记录为空时,
id
设置为1
。 - 当角色表记录不为空时,
id
设置为当前id
加3
MyBatis
对这样的场景也提供了支持,它主要依赖于selectKey
元素进行支持,它允许自定义键值的生成规则。
|
|
- 它定义了
selectKey
元素,它的keyProperty
指定了采用哪个属性作为POJO
的主键。 resultType
告诉MyBatis
将返回一个long
型的结果集,而order
设置为BEFORE
,说明它将于当前定义的SQL
前执行。- 这里的
order
配置为BEFORE
,说明它会在插入之前会先执行生成主键的SQL
,然后插入数据。
5.4 update元素和delete元素
update
和delete
执行完会返回一个整数,用以标识该SQL语句影响数据库的记录行数
|
|
5.5 sql元素
sql元素的作用在于可以定义一条SQL
的一部分,方便后面的SQL引用它,比如最典型的列名。通常情况下要在select
、insert
等语句中反复编写它们,特别是那些字段较多的表更是如此。
|
|
sql元素还支持变量传递
|
|
5.6 参数
5.6.1 概述
一些数据库字段返回为null
,而MyBatis
系统又检测不到使用何种jdbcType
进行处理时,会发生异常的情况,这个时候执行对应的typeHandler
进行处理,MyBatis
就知道采取哪个typeHandler
进行处理了
|
|
而事实是,大部分情况下都不需要这样编写,因为MyBatis
会根据javaType
和jdbcType
去检测使用哪个typeHandler
|
|
5.6.2 存储过程参数支持
MyBatis对存储过程也进行了支持,在存储过程中存在:输入(IN)参数、输出(OUT)参数和输入输出(INOUT)参数3种类型。
5.6.3 特殊字符串的替换和处理
在现实中,由于一些因素会造成构成SQL
查询的列名发生变化,比如产品类型为大米,查询的列名是重量,而产品类型为灯具,查询的列名是数量,这时候需要构建动态列名。有些企业会将一张很大的数据库表按年份拆分,比如购买记录表(t_purchase records
) 。现实中由于记录比较多,可能为了方便按年份拆分为t_purchase_records_ 2016
、t_purchase_records_ 2017
、t_purchase_records_2018
等,这时往往需要构建动态表名。
在MyBatis
中,构建动态列名常常要传递类似于字符串的columns="coll, col2, col3 ..."
给SQL
,让其组装成为SQL
语句。如果不想被MyBatis
像处理普通参数一样把它设为"coll, col2, col3 ..."
,那么可以写成select ${columns} from t_tablename
,这样MyBatis
就不会转译columns
,而不是作为SQL
的参数进行设置了,这句SQL
就会变为select col1, col2, col3 ... from t_tablename
。
5.7 resultMap元素
resultMap
的作用是定义映射规则、级联的更新、定制类型转化器等。resultMap
定义的主要是一个结果集的映射关系,也就是SQL
到Java Bean
的映射关系定义,它也支持级联等特性。只是MyBatis
现有的版本只支持resultMap
查询,不支持更新或者保存,
5.7.1 resultMap元素的构成
resultMap
元素的子元素
|
|
5.7.2 使用map存储结果集
一般而言,任何select
语句都可以使用map
存储
|
|
使用map原则上是可以匹配所有的结果集的,但是使用map接口就意味着可读性的下降
5.7.3 使用POJO存储结果集
使用map
方式就意味着可读性的丢失,POJO
是最常用的方式。有时候需要更为复杂的映射或者级联,这个时候还可以使用select
语句的resultMap
属性配置映射集合
|
|
resultMap
元素的属性id
代表这个resultMap
的标识,type
代表着需要映射的POJO
,这里可以使用MyBatis
定义好的类的别名,也可以使用自定义的类的全限定名。在映射关系中,id
元素表示这个对象的主键,property
代表着POJO
的属性名称,column
表示数据库SQL
的列名,于是POJO
就和数据库SQL
的结果一一对应起来了
5.8 级联
级联是一个数据库实体的概念。比如角色就需要存在用户与之对应,这样就有角色用户表,一个角色可能有多个用户,这就是一对多的级联;除此之外,还有一对一的级联,比如身份证和公民是一对一的关系。在MyBatis中还有一种被成为鉴定器的级联,它是一种可以选择具体实现类的级联
级联不是必须的,级联的好处是获取关联数据十分便捷,但是级联过多会增加系统的复杂度,同时降低系统的性能
5.8.1 MyBatis中的级联
MyBatis
的级联分为3种。
- 鉴别器(
discriminator
):它是一个根据某些条件决定采用具体实现类级联的方案,比如体检表要根据性别去区分。 - 一对一(
association
):比如学生证和学生就是一种一对一的级联,雇员和工牌表也是一种一对一的级联。 - 一对多(
collection
):比如班主任和学生就是一种一对多的级联。
为了更好地阐述级联,先给出一个雇员级联模型
5.8.2 N+1问题
通过级联,我们可以拿出所有关联数据,但这样会引发性能问题。因为有些性能并不常用,加载它们会多执行几条毫无用处的SQL
,导致数据库资源的损耗和系统性能的下降,这就是N+1问题
为了应对N+1问题,MyBatis提供了延迟加载功能
5.8.3 延迟加载
在MyBatis
的setting
配置中存在两个元素可以配置级联
lazyLoadingEnabled
是一个开关,决定开不开启延迟加载,默认值为false
,则不开启延迟加载
aggressiveLazyLoading
配置项是一个层级开关,当设置为true
时,它是一个开启了层级开关的延迟加载
此外,在MyBatis
中使用fetchType
属性,可以处理全局定义无法处理的问题,fetchType
出现在级联元素(association
、collection
),它存在两个值
eager
,获取当前POJO
后立即加载对应数据lazy
,获取当前POJO
后延迟加载对应的数据
5.9 缓存
在MyBatis
中允许使用缓存, 缓存一般都放置在可高速读/写的存储器上,比如服务器的内存,它能够有效提高系统的性能。一般只会把那些常用且命中率高的数据缓存起来,以便将来使用,而不缓存那些不常用且命中率低的数据缓存。
5.9.1 一级续存和二级缓存
一级缓存是在SqlSession
上的缓存,二级缓存是在SqlSessionFactory
上的缓存。默认情况下,也就是没有任何配置的情况下,MyBatis
系统会开启一级缓存,也就是对于SqlSession
层面的缓存,这个缓存不需要POJO
对象可序列化。
为了使SqlSession
对象之间共享相同的缓存,有时候需要开启二级缓存,开启二级缓存很简单,只要在映射文件(RoleMapper.xml
)上加入代码:
|
|
这个时候MyBatis
会序列化和反序列化对应的POJO
,也就要求POJO
是一个可序列化的对象,那么它就必须实现java.io.Serializable
接口。
5.9.2 自定义缓存
MyBatis
可以使用自定义的缓存,只是实现类需要实现MyBatis
的接口org.apache.ibatis.cache.Cache
,让我们看看Cache
接口
|
|
在现实中,我们可以使用Redis
,MongoDB
或者其他常用的缓存,假设存在一个Redis
的缓存实现类com.ssm.chapter5.cache.RedisCache
,那么可以这样配置它:
|
|
5.10 存储过程
略
[SSM][5][映射器]相关推荐
- 《Java EE SSM框架》学习笔记(5、映射器)
demo链接地址:https://share.weiyun.com/5iCY76r 密码:hxf568 不使用注解的方式,实现映射器: 1.面对复杂性,SQL会显得无力. 2.注解的可读性较差. 3. ...
- SpringMVC - 非注解的处理器映射器和适配器
为什么80%的码农都做不了架构师?>>> 一.非注解的处理器映射器 提供的处理器有两个属性.一个是id属性,一个是name属性.分别对应两种不同的映射器. <bean i ...
- 处理器映射器(HandlerMapping)及处理器适配器(HandlerAdapter)详解(一)
非注解 处理器映射器 和 处理器适配器 处理器映射器: 第一种: BeanNameUrlHandlerMapping <!-- 配置Handler --> <bean id=&quo ...
- 【SpringMVC框架】注解的处理器映射器和适配器配置
下面我们来探讨注解的处理器映射器和适配器 1.注解的处理器映射器和适配器 在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.De ...
- 【SpringMVC框架】非注解的处理器映射器和适配器
非注解的处理器映射器和适配器 1.非注解的处理器映射器 之前的处理器映射器: org.springframework.web.servlet.handler.BeanNameUrlHandlerMap ...
- SpringMVC学习记录二——非注解和注解的处理器映射器和适配器
3 非注解的处理器映射器和适配器 3.1 非注解的处理器映射器 处理器映射器: org.springframework.web.servlet.handler.BeanNameUr ...
- 【Java EE】映射器
映射器 映射器是MyBatis最复杂且最重要得组件,它由一个接口加上XML文件(或者注解)组成.在映射器中可以配置参数.各类的SQL语句.存储过程.缓存.级联等复杂的内容,并且通过简易的映射规则映射到 ...
- 深入MyBatis开发之mybatis映射器
映射器的配置元素有select/insert/update/delete/sql/resultMap/cache/cache-ref八个常用的,parameterMap基本不用,也不建议使用. MyB ...
- Nmap (网络映射器)好东西啊
2019独角兽企业重金招聘Python工程师标准>>> Nmap (网络映射器)是由 Gordon Lyon设计,用来探测计算机网络上的主机和服务的一种安全扫描器.为了绘制网络拓扑 ...
最新文章
- OCR:精准、稳定、易用的文字识别
- matlab训练集测试集划分
- VTK:绘制Arrow箭头用法实战
- 怎么才能让计算机发出音乐,我要怎样把电脑上的歌曲传到手机里去啊?-怎么能把电脑里面的歌...
- python与C、C++混编的四种方式
- python getattr_Python 内置方法和属性应用:反射和单例
- leetcode887 鸡蛋掉落
- idea通过数据库生成实体类插件_IDEA连接数据库自动生成实体类
- android确定工作日,如何确定某个月的最后一个工作日?
- linux 内核块设备驱动,linux之块设备驱动
- pycharm查询mysql数据库_pycharm访问mysql数据库的方法步骤
- 置换检验 配对秩和检验
- Excel怎么转换成PDF?这两招轻松解决
- iOS之推荐六款不错的 iOS 15 Safari 浏览器扩展
- vue中的@click.native.prevent,点击事件加上native.prevent究竟有什么用呢?
- Latex标题页上标和脚注的处理方法 如何在latex文件中添加footnote
- 张学友-歌神同行.叁(国语篇)2019【SACD-ISO】
- mint-ui —— checklist的使用
- 精通mysql索引机制,你就不用再背sql优化口诀了!!(万字长文)
- 【JAVA】计算算式
热门文章
- 百度元宵晚会再发 2 亿红包;淘宝 2400 万情侣绑亲情账号;苹果春季发布会倒计时 | 极客头条...
- 源码免费下载!分享一套基于C6678+K7的视频采集处理方案
- Vue中设置全局变量
- CPU核心数和线程数的关系
- 如何查看MySQL当前连接数
- 端口号8080被占用,解决办法
- A、B、C、D、E类网络地址
- 生成订单php setinc,ThinkPHP 统计数据(数字字段)更新 setInc 与 setDec 方法,加减...
- scrapy爬虫框架及运行流程
- three 天空球_three.js添加场景背景和天空盒(skybox)