深入理解MyBatis的原理(四):映射器的用法
前言:继续深入学习 mybatis 的用法及原理,还是先会用再学习原理。
映射器的主要元素有:select、insert、update、delete、parameterMap(即将被删除,不建议使用)、sql、resultMap、cache、cache-ref
各个元素的规则定义:见源码中的文件 org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd
目录:
一、select 元素
1、查询,select 元素有以下属性:
id:和 Mapper 的命名空间组合起来必须是唯一的,供给 MyBatis 上下文调用。
parameterType:查询参数类型。一般给出类的全命名,也可以给出类的别名。可以选择 JavaBean、Map 等复杂的参数类型传递给 SQL。
resultType:查询返回数据类型。一般给出类的全命名,或者别名,不能和 resultMap 同时使用。
resultMap:查询返回映射集的引用,将执行强大的映射功能。不能和 resultType 同时使用。它是 MyBatis 最复杂的元素,可以自定义映射规则、级联、typeHandle 等。
flushCache:它的作用是在调用 SQL 后,是否要求 MyBatis 清空之前查询的本地缓存和二级缓存。取值为 boolean,默认 false。
useCache:启动二级缓存的开关,是否要求 MyBatis 将此次结果缓存。取值为 boolean,默认 true。
timeout:这是超时参数,等超时的时候将抛出异常,单位为秒。默认值为数据库厂商提供的 JDBC 驱动所设置的秒数。
fetchSize:获取记录的总条数。默认值为数据库厂商提供的 JDBC 驱动所设置的条数。
statementType:选择使用 JDBC 的 Statement 工作,取值为 STATEMENT、PREPARED、CallableStatement。默认 PREPARED。
resultSetType:很少使用
databaseId:数据库厂商标识,提供多数据库的支持。
resultOrdered:很少使用
resultSets:很少使用
2、举例
dao 接口
/**
* 通过名字查找用户
* @param name
* @return
*/
User queryUserByName(String name);
xml
<select id="queryUserByName" resultType="com.yule.user.entity.User">
select t.id, t.name, t.age from t_user t
where t.name = #{name,jdbcType=VARCHAR}
</select>
3、自动映射
当配置 autoMappingBehavior 不是 NONE 时,MyBatis 会提供自动映射功能,只要返回的 sql 列名(别名)和 JavaBean 的属性一致,MyBatis 就会帮助我们回填这些字段无需任何配置,它可以在很大程度上简化我们的配置工作。
在实际中,通常我们是使用 sql 列名的别名的方式自动映射。上方例子的 resultType="com.yule.user.entity.User" 就是 MyBatis 的自动映射。
在实际中,也可以通过在配置文件中开启驼峰命名方式:mapUndersoreToCamlCase 为 true。这种方式的前提是数据库命名是规范的,即每一个单词都用下划线分割,POJO 采用的是驼峰命名方式,那么可以设置配置文件,从而达到从数据库到 POJO 的自动映射了。
自动映射在 MyBatis 的配置文件中,元素 settings 中可以配置 autoMappingBehavior 属性值来设置其策略,它包含 3 个值:
- NONE:取消自动映射
- PARTIAL:只会自动映射,没有定义嵌套结果集映射的结果集。为默认值。
- FULL:会自动映射任意复杂的结果集(无论是否嵌套),性能会下降。
在大部分的情况下 MyBatis 都会推断你返回数据的类型,所以大部分情况下你都无需去配置参数类型和结果类型。要我们设置的往往只是可能返回为空的字段类型而已。因为 null 值,MyBatis 无法判断其类型。
4、传递多个参数
一、使用 map,缺点是业务关联性不强,造成代码可读性下降。
二、使用注解 @Param,xml 中无需定义参数类型。可读性增强,但是当参数个数太多时,可读性仍然会下降。
三、使用 JavaBean 传递参数。
这三种方式对比:
- 使用 Map 传递参数。因为 Map 导致代码的可读性下降,会导致后面的扩展和维护比较困难,所以建议少使用这种方式。
- 使用 @Param 注解方式。这种方式可读性高,但是当参数个数很多的时候,同样会导致可读性和维护性下降,所以,当参数个数小于等于 5 时,建议采取这种方式。
- 使用实体 JavaBean 的方式。当参数个数大于 5 时,建议采取这种方式。
5、使用 resultMap 映射结果集
对于简单的映射,建议采用自动映射就好,可以减少配置。resultMap 映射一般就用于复杂、级联这些关联的配置。所以这个放在 resultMap 结果映射集讲。
二、insert 元素
1、插入,insert 元素有一下属性:
id:同 select
parameterType:同 select
flushCache:同 select
timeout:同 select
statemeterType:同 select
keyProperty:表示以哪个列作为属性的主键。不能和 keyColumn 同时使用。联合主键可以用逗号隔开。
useGeneratedKeys:这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出数据库内部生成的主键,使用该属性后就必须使用keyColumn或者KeyProperty属性中的一个。取值为 boolean 值,默认 false。
keyColumn:指明第几列是主键。不能和 keyProperty 同时使用。联合主键可以用逗号隔开。只接受整形参数。
databaseId:同 select
lang:使用很少
2、举例
dao 接口
/**
* 新增用户
* @param user
* @return
*/
int insertUser(User user);
xml,自定义规则:使用序列实现主键回填,即执行完新增后返回主键 id。这个能把主键 id 回填到实体 User 上去。
MyBatis 中 不允许同事包含连两个 selectKey 标签。
<insert id="insertUser">
<selectKey keyProperty="id" order="BEFORE" resultType="int">
select t_user_s.nextval from dual
</selectKey>
insert into t_user
(id, name, age)
values
(#{id}, #{name}, #{age})
</insert>
测试
@Test
public void testInsertUser(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao mapper = sqlSession.getMapper(UserDao.class); User user = new User("yule", "24"); mapper.insertUser(user); sqlSession.commit();
sqlSession.close(); System.out.println(user.toString());
}
3、举例2
xml,使用主键自增长(必须在表中设置 id 字段为自增字段),同时 sql 执行完成之后 MyBatis 自动将执行完 sql 后自动生成的 id 回填到我们的参数 User 对象中。
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user
(name, age)
values
(#{name}, #{age})
</insert>
三、update 元素
1、修改,和 insert 一样,MyBatis 执行完后会返回一个整数,标出执行后影响的条数。
2、举例
dao 接口
/**
* 修改用户信息
* @param user
* @return
*/
int updateUserById(User user);
xml
<update id="updateUserById">
update t_user t set t.age = #{age}, t.name = #{name}
where t.id = #{id}
</update>
四、delete 元素
1、删除,和 insert 一样,MyBatis 执行完后会返回一个整数,标出执行后影响的条数。
2、举例
dao 接口
int deleteUserById(String id);
xml
<delete id="deleteUserById">
delete t_user t where t.ID = #{id}
</delete>
五、参数
定义参数属性时,MyBatis 不允许换行!!!
1、参数配置
我们可以通过制定参数的类型去让对应的 typeHandle 处理它们,也可以通过指定对应的 JavaType、JdbcType 来明确使用哪个 typeHandle 处理参数。详见 https://www.cnblogs.com/yuxiaole/p/9464019.html#typeHandler
2、存储过程支持
对于存储过程而言,存在 3 种参数,输入参数(IN)、输出参数(OUT)、输入输出参数(INOUT)。MyBatis 的参数规则为其提供了良好的支持。
3、特殊字符串替换和处理(# 和 $)
使用 #{} 方式,MyBatis 会用创建预编译的语句,然后 MyBatis 为它设值。
使用 ${} 方式,传递 SQL 语句本身,比如传递 SQL 的列名、根据某些列排序等。比如 select ${columns} from t_tablename 来支持传递动态列名。不过使用这种方式是不安全的,所以虽然 MyBatis 是给了灵活性,但是自己也需要控制参数来保证 SQL 运转的正确性和安全性。
六、SQL 片段重用
采用 <include refid="sql_id"></include> 来实现 SQL 片段的重用。SQL 片段是指用 <sql></sql> 定义的片段。
比如:给 include 标签加一个 refid 属性进行引用,从而达到重用的功能
<sql id="user_columns">
${prefix}.id, ${prefix}.name, ${prefix}.age
</sql>
<select id="queryUserByName" resultType="com.yule.user.entity.User">
select
<include refid="user_columns">
<property name="prefix" value="t"/>
</include>
from t_user t
where t.name = #{name,jdbcType=VARCHAR}
</select>
或者,可以直接给 refid 一个参数值,由程序制定引入 SQL
<select id="queryUserList" resultType="User" >
<include refid="common_query">
<property name="columnsName" value="user_columns"/>
</include>
</select>
<sql id="common_query">
select
<include refid="${columnsName}">
<property name="prefix" value="t"/>
</include>
from t_user t
</sql>
七、resultMap 结果映射集
resultMap 是 MyBatis 中最复杂的元素。主要是定义一个查询中的结果集的映射关系,不支持修改、删除。作用是定义映射规则、级联的更新、定制类型转换器等。
1、resultMap 元素里面的构成
见源码:org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd
<!ELEMENT resultMap (constructor?,id*,result*,association*,collection*, discriminator?)>
其中,constructor 元素用于配置实体构造方法。表示告诉 MyBatis 用实体的哪个构造方法来构造实体。
<!ELEMENT constructor (idArg*,arg*)>
其中,id 元素是表示哪个列是主键,允许多个主键,多个主键称为联合主键。
其中,result 元素是配置 POJO 到 SQL 列名的映射关系。
result 和 id 两个元素都有如下属性:
- property:代表 POJO 的属性名称。映射到列结果的字段或属性,如果 POJO 的属性匹配是存在的,和给定 SQL 列名(column 元素)相同的,那么 MyBatis 就会映射到 POJO 上。
- column:对应的是 SQL 的列名。
- javaType:配置 Java 的字段类型
- jdbcType:配置数据库中的字段类型
- typeHandle:类型处理器
2、使用 map 存储结果集
select 元素中使用 resultMap 会使可读性下降,所以建议更多时候使用 POJO 的方式来自动映射,即 resultType。
resultMap 元素的属性 id 代表这个 resultMap 的标识,type 代表需要映射的 POJO。
<!ATTLIST resultMap
id CDATA #REQUIRED
type CDATA #REQUIRED
extends CDATA #IMPLIED
autoMapping (true|false) #IMPLIED
>
举例:SQL 语句的列名需要和 column 一 一对应。
<resultMap id="userResultMap" type="com.yule.user.entity.User">
<constructor>
<idArg column="id" javaType="string"/>
<arg column="name" javaType="string"/>
<arg column="age" javaType="string"/>
</constructor>
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
</resultMap>
<select id="queryUserById" resultMap="userResultMap">
select t.id, t.name, t.age from t_user t
where t.id = #{id}
</select>
3、级联
有 3 中关系:一对一、一对多、多对多。多对多可用一对多双向标识。
在 MyBatis 中级联分为这么 3 种:
- association:一对一。
- collection:一对多。
- discriminator:鉴别器。可以根据实际选择采用哪个类作为实例,允许根据特定的条件去关联不同的结果集。
举例:
深入理解MyBatis的原理(四):映射器的用法的更多相关文章
- SiteMesh2-sitemesh.xml的其它映射器的用法
在sitemesh.xml中做常用的三个映射器,总结如下: 映射器元素的顺序确定优先级.良好的应用程序应使用以下顺序, Parameter query = ParameterDecoratorMapp ...
- 深入理解MyBatis的原理:整个体系
前言:工作中虽然用到了 MyBatis,可完全不知道为什么,再不学习就晚了,这里将记录我的学习笔记,整个 MyBatis 的体系. 一.简介 1.传统的JDBC JDBC 是一种典型的桥接模式. 使用 ...
- 深入理解MyBatis的原理(一): 独立的入门demo
前言:不结合spring,只有 mybatis+maven.数据库使用 oracle.不尝试永远不知道会发生什么事,其中遇到两个小问题,也记录下来了.转载请注明出处:https://www.cnblo ...
- 深入理解MyBatis的原理(三):配置文件用法(续)
前言:前文讲解了 MyBatis 的配置文件一部分用法,本文将继续讲解 MyBatis 的配置文件的用法. 目录 1.typeHandler 类型处理器 2.ObjectFactory 3.插件 4. ...
- 深入理解MyBatis的原理(三):配置文件(上)
前言:前文提到一个入门的demo,从这里开始,会了解深入 MyBatis 的配置,本文讲解 MyBatis 的配置文件的用法. 目录 1.properties 元素 2.设置(settings) 3. ...
- SiteMesh2-sitemesh.xml的ParameterDecoratorMapper映射器的用法
继续使用上一章http://www.cnblogs.com/EasonJim/p/7086916.html的例子,改造成使用ParameterDecoratorMapper映射器的方法,这个映射器不需 ...
- SiteMesh2-sitemesh.xml的ConfigDecoratorMapper映射器的用法
继上一次的示例工程http://www.cnblogs.com/EasonJim/p/7083165.html,使用的就是ConfigDecoratorMapper映射器,通过指定目录下的页面,都同一 ...
- SiteMesh2-sitemesh.xml的PageDecoratorMapper映射器的用法
继上一章http://www.cnblogs.com/EasonJim/p/7083165.html中使用的例子中,是通过decorators.xml文件通过URL匹配进行转换的. 而下面这种方法是通 ...
- mybatis精讲(五)--映射器组件
目录 前言 标签 select insert|update|delete 参数 resultMap cache 自定义缓存 # 加入战队 微信公众号 前言 映射器之前我们已经提到了,是mybatis特 ...
随机推荐
- 二,windows下安装memcached服务
window下安装memcached服务的流程如下: 1. 下载memcache的windows稳定版,解压放某个盘下面,比如在c:\memcached 2. 在终端(也即cmd命令界面)下输入 ‘c ...
- Kafka网络模型分析
Kafka基于高吞吐率和效率考虑,并没有使用第三方网络框架,而且自己基于java nio封装的,总体网络模型如下: Broker的内部按照SEDA模型处理网络请求,处理过程如下: Accept Thr ...
- android 代码实现back键功能
方案一,简单但响应慢: doExec("input keyevent 4"); public String doExec(String cmd) { String s = &quo ...
- iOS开发--应用国际化,应用内切换语言
1.前言 自己负责的项目需要做国际化,并且要求应用内部切换语言.这个是可以做到的,也并不难,可以直接戳Github看一下 https://github.com/leo90821/Localiztion ...
- 【xsy1504】 pitcure 树状数组
数据范围:$n≤2\times 10^5$ 以下是题解: #include<bits/stdc++.h> #define L unsigned int #define MOD 167772 ...
- Swift Podfile中的 use_frameworks!
use_frameworks! A.用cocoapods 导入swift 框架 到 swift项目和OC项目都必须要 use_frameworks!B.使用 dynamic frameworks,必须 ...
- 微信小程序web-view(webview) 嵌套H5页面 唤起微信支付的实现方案
场景:小程序页面有一个web-view组件,组件嵌套的H5页面,要唤起微信支付. 先讲一下我的项目,首先我是自己开发的一个H5触屏版的商城系统,里面含有购物车,订单支付等功能.然后刚开始,我们公众号里 ...
- 关于JSON基础的总结
本文总结自百度百科 JSON 语法规则 JSON 语法是 JavaScript 对象表示语法的子集. 数据在键值对中 数据由逗号分隔 花括号保存对象 方括号保存数组 JSON 名称/值对 JSON 数 ...
- puppet的使用:puppet的hello world
这个例子完成将master节点上的一个文件放至agent节点上的功能 创建要传输的文件 echo "helloWorld" > /etc/puppet/modules/pup ...
- LINUX 下 NMAP 内网扫描
#1.扫描内网存活主机 nmap -sP 10.2.24.* |grep for > tmp #2.扫描主机端口 nmap -A -T4 192.168.1.2 #3.扫描主机的所有端口 nma ...