转自:https://blog.csdn.net/chris_mao/article/details/48811507

Mybatis的真正强大,在于她对SQL的映射,这也是她吸引人的地方。实现相同的功能,她要比直接使用JDBC省去95%的代码量。而且将 SQL语句独立在Java代码之外,为程序的修改和纠错提供了更大的灵活性,可以直接修改SQL语句,而无需重新编译Java程序。

本文将在上一篇《Mybatis系列之简单示例》的基础上,对映射文件进行详细的讨论学习。

SQL映射文件也是XML格式,其顶级元素有以下几个:

  • select - 映射sql查询语句
  • insert - 映射sql插入语句
  • update - 映射sql更新语句
  • delete - 映射sql删除语句
  • sql - 就像程序中可以复用的函数一样,这个元素下放置可以被其他语句重复引用的sql语句
  • resultMap - 用来描述如何从数据库查询结果集中来加载对象
  • cache - 给定命名空间的缓存配置
  • cache-ref - 其他命名空间缓存配置引用
下面从语句本身开始,在上一篇《Mybatis系列之简单示例》的基础上,为大家一一阐述各元素用法。

查询语句映射

查询语句,是sql中使用频率最高的语句,Mybatis中的查询语句映射也是很简单的。如:

  1. <select id="getById" parameterType="int" resultType="User">
  2. SELECT <span style="font-family: Arial, Helvetica, sans-serif;">user_name, user_password, nick_name, email, user_type_id, </span><span style="font-family: Arial, Helvetica, sans-serif;">is_valid, created_time</span>
  3. FROM sys_user WHERE user_id = #{id}
  4. </select>

这是一条被称作getById的查询,需要一个类型为int或是Integer的参数,查询返回一个User类型对象,对象的属性名称就是查询语句中的列名,属性值就是查询结果行中对应的值。


注意,上句话中斜体加粗部分,“查询语句中的列名”意味着在对查询结果进行实体映射时,使用的是查询语句中的列名进行映射的,而非数据表中的。举例说
明:select user_name .....,那么对应的实体对象属性名称就是user_name;如果在查询时使用了别名,如select
user_name as userName,那么对应的实体对象的属性名称就是userName。

通常情况下,数据表对字段命名规则使用
下划线进行分词的,而Java中却是使用驼峰式的命名规则,那么是不是意味着我们在数据表中也要使用驼峰式命名规则,或是在查询语句中都要使用别名方式
呢?其实完全不必,Mybatis早早就替我们考虑到这点的,在Mybatis核心配置文件中,只需要添加以下代码,Mybatis就可以自动的将
a_column转换为aColumn。

  1. <settings>
  2. <!-- 将数据库字段命名规则A_COLUMN转换为Java使用的驼峰式命名规则aCloumn -->
  3. <setting name="mapUnderscoreToCamelCase" value="true" />
  4. </settings>

请注意select元素中#{id}的用法,这里就是告诉Mybatis创建一个预处理语句参数,通过JDBC,这样的参数在sql中会是用一个"?"来标识,并被传递到预处理语句中。就像下面这段代码:

  1. // Similar JDBC code, NOT MyBatis…
  2. String getById = "SELECT user_name, user_password, nick_name, email, user_type_id, is_valid, created_time FROM sys_user WHERE user_id=?";
  3. PreparedStatement ps = conn.prepareStatement(getById);
  4. ps.setInt(1,id);

当然,在获得结果集后,我们还需要额外编写很多代码,将结果集的中数据映射到一个Java对象上。如果使用Mybatis,这些全部省去了,想想都很让人兴奋。(Mybatis会将#{与}之间的内容转换为预处理语句中的"?"

select语句有,有很多属性允许我们来配置,以决定每条sql语句的作用细节。

  id="getById"
parameterType="int"
parameterMap="deprecated"
resultType="User"
resultMap="userResultMap"
flushCache="false"
useCache="true"
timeout="10000"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
属性

描述
id 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。
从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。
resultMap 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false。
useCache 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。
fetchSize STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetType 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
resultOrdered false。
这个设置仅对多结果集的情况适用,它将列出语句执行后返回的结果集并每个结果集给一个名称,名称是逗号分隔的。

在映射文件中定义好查询语句之后,就可以在Java代码中做如下调用:(这里插播个预告,在后面的《Mybatis系列之接口方式编程》中,我们会使用一个更简洁的方式来调用映射文件中的sql语句)

  1. @Test
  2. public void testGetById() {
  3. SqlSession session = sqlSessionFactory.openSession();
  4. try {
  5. User user;
  6. Object obj = session.selectOne("com.emerson.learning.mapping.user.getByID", 1);
  7. if (null == obj) {
  8. System.out.println("the result is null.");
  9. } else {
  10. user = (User) obj;
  11. System.out.println(user);
  12. }
  13. } finally {
  14. session.close();
  15. }
  16. }

插入语句映射

插入语句和查询语句类似,也需要定义唯一的id,指定传入参数类型。

  1. <!-- 写入新记录并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
  2. <insert id="insertUser" parameterType="User" useGeneratedKeys="true"
  3. keyProperty="userId">
  4. INSERT INTO sys_user(user_name, user_password, nick_name,
  5. user_type_id, is_valid, created_time)
  6. VALUES(#{userName},
  7. #{userPassword}, #{nickName}, #{userTypeId}, #{isValid},
  8. #{createdTime})
  9. </insert>

针对插入语句,这里有一点需要进行特别说明,那就是如何获得新插入数据的主键值。

在允许使用自增长字段做为主键的数据库中(如MSSQL,MySQL),我们只需要在insert元素中增加两个属性值即可。如:

  1. <insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="userId">

将属性userGeneratedKeys设为true,并将KeyProperty属性设为数据表主键对应的实体对象属性名称。这句话有点绕,我们就以上面这条插入语句为例,数据表中主键是user_id,对应的实体对象中的属性名称是userId,所以这里我们就把userId高为KeyProperty的值。

在不允许有自增字段的数据库中(如Oracle数据库),Mybatis有另外一种方法生成数据表主键,即在insert元素内部增加一个selectKey元素,用于生成数据表主键。如

  1. <insert id="insertUser" parameterType="User">
  2. <selectKey keyProperty="userId" resultType="int" order="BEFORE">
  3. select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
  4. </selectKey>
  5. INSERT INTO sys_user(user_name, user_password, nick_name,
  6. user_type_id, is_valid, created_time)
  7. VALUES(#{userName},
  8. #{userPassword}, #{nickName}, #{userTypeId}, #{isValid},
  9. #{createdTime})
  10. </insert>
selectKey属性

属性

描述
keyProperty 匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
resultType
可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty
然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素 - 这和像 Oracle
的数据库相似,在插入语句内部可能有嵌入索引调用。
statementType
  • public void testInsertUser() {
  • SqlSession session = sqlSessionFactory.openSession();
  • try {
  • User user = new User();
  • user.setEmail("chris.mao.zb@163.com");
  • user.setNickName("Chris Mao");
  • user.setUserName("cmzb");
  • user.setIsValid(1);
  • user.setUserPassword("5f4dcc3b5aa765d61d8327deb882cf99");
  • <span class="s1" style="font-family: Arial, Helvetica, sans-serif;">int</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;"> </span><span style="font-family: Arial, Helvetica, sans-serif;">effectedRows</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;"> = </span><span style="font-family: Arial, Helvetica, sans-serif;">session.insert("com.emerson.learning.mapping.user.insertUser", user); </span><span style="font-family: Arial, Helvetica, sans-serif;">assertEquals(</span><span class="s1" style="font-family: Arial, Helvetica, sans-serif;">effectedRows</span><span style="font-family: Arial, Helvetica, sans-serif;">, 1);</span><span style="font-family: Arial, Helvetica, sans-serif;">
  • lt;/span>            System.out.println("New Id is " + user.getUserId());
  • session.commit();
  • } finally {
  • session.close();
  • }
  • }
  • 更新语句映射

    1. <update id="udpateUser" parameterType="User">
    2. UPDATE sys_user
    3. SET user_name = #{userName}, user_password = #{userPassword},nick_name = #{nickName},user_type_id = #{userTypeId},is_valid = #{isValid}
    4. WHERE user_id = #{<span style="font-family: Arial, Helvetica, sans-serif;">userId</span><span style="font-family: Arial, Helvetica, sans-serif;">}</span>
    5. </update>

    删除语句映射

    1. <delete id="deleteById" parameterType="int">
    2. DELETE FROM sys_user WHERE user_id = #{id}
    3. </delete>

    SQL

    这个元素用来定义可以重复使用的sql语句。可复用的不一定要是一个完整的sql语句,也可以是sql语句中的一部分,如字段名称等。

    以查询和插入为例,我们在查询语句中会写出好多的列名称;同样,在插入语句时也要写出这些字段名称,那么这时,我们就可以把这部分重复的sql语句单独拿出来定义。如

    1. <sql id="columns">user_name, user_password, nick_name, email, user_type_id,
    2. is_valid, created_time</sql>
    3. <!-- 根据传入的Id值,到数据库中查询记录 -->
    4. <select id="getByID" parameterType="int" resultType="User">
    5. SELECT
    6. <include refid="columns"></include>
    7. FROM sys_user WHERE user_id = #{id}
    8. </select>
    9. <!-- 按用户名进行模糊查询 -->
    10. <select id="queryByName" parameterType="User" resultType="User">
    11. SELECT
    12. <include refid="columns"></include>
    13. FROM sys_user
    14. <where>
    15. <if test="userName != null">user_name like '%' #{userName} '%'</if>
    16. </where>
    17. </select>
    18. <!-- 创建新用户,并写入到数据表中 -->
    19. <!-- 写入新记录并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
    20. <insert id="insertUser" parameterType="User" useGeneratedKeys="true"
    21. keyProperty="userId">
    22. INSERT INTO sys_user(<include refid="columns"></include>)
    23. VALUES(#{userName},
    24. #{userPassword}, #{nickName}, #{userTypeId}, #{isValid},
    25. #{createdTime})
    26. </insert>

    查询参数

    通过上面部分的讲解,细心的朋友已经发现了,Mybatis是使用#{}来定义参数的,出现在sql语句中的#{}都会为转换为预处理语句中的"?"。

    如果参数是简单类型,如int, string等,则#{}中写什么名称什么名称都可以,或是写成通用的#{_parameter}。这种写法仅限于简单数据类型。

    如果参数是一个自定义类型,则#{}中写的就是相应的属性名称,如#{userName},#{nickName}。

    Mybatis还定义了另外一种参数形式,就是${}。这个可以理解成一个占位符,她会被替找成传入的值。


    认情况下,使用#{}格式的语法会导致Mybatis创建预处理语句属性,并安全地设置传入值(比如会自动对字符型数据两边加上引号等)。这样做更安全、
    更迅速,也是道选做法。不过有时只是想直接在sql语句中原样不变地插入一个字符串,比如ORDER BY  ${COLUMN}。

    查询结果集

    ResultMap是Mybatis最重要、最强大,也是相对最复杂的一个元素。这里就不多做说明,待后续文章《Mybatis系列之一对多关系》时再做具体讲解。

    缓存

    Mybatis包含了一个很强大的缓存特性,可以非常方便地配置和使用。默认情况下,缓存功能是没有开启的。要想使用缓存只需要sql映射文件中加入cache元素即可。
     
    1. <cache />

    这个简单语句效果如下:

    • 映射文件中所有的select语句都将会被缓存
    • 映射文件中所有的insert / update / delete语句会刷新缓存
    • 缓存默认使用LRU最近最少使用算法来回收
    • 根据时间表,缓存不会以作何时间顺序来刷新
    • 缓存最多会存储列表集合或是对象的1024个引用
    • 缓存被视为可读、写缓存,这意味着对象检索不是共享的,且可以安全地被调用者修改,而不干拢其他调用过或线程所做的潜在修改。
    所有这些属性,都可以通过cache元素的属性进行修改配置。如
    1. <cache
    2. eviction="FIFO"
    3. flushInterval="60000"
    4. size="512"
    5. readOnly="true"/>

    这个算法将缓存的回收策略改为了先进先出,并且每隔60秒刷新一次,最大缓存对象引用数量为512,且返回的对象是只读的,因此在不同线程中的调用者修改它们会导致冲突。

    Mybatis中回收策略有以下几种:
    • LRU - 最近最少使用的:移除最长时间不被使用的对象
    • FIFO - 先进先出:按对象进入缓存的时间顺序来移除
    • SOFT - 软引用:移除基于垃圾回收器状态和软引用规则的对象
    • WEAK - 弱引用:更积极地移除基于垃圾回收器状态和弱引用规则的对象
    flushInterval,刷新间隔,可以被设置为任意的正整数,代表每隔多少毫秒进行一次刷新动作。默认情奖品是不设置,也就是没有刷新间隔,缓存仅仅在有sql语句被调用时刷新。
    size,最大引用数量,可以被设置为任意的正整数。默认是1024
    readOnly,
    只读属性,可以被设为true 或
    false。只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改。这提供了很重要的性能优势。可读写缓存则返回对象的拷贝,这样在
    性能上会有一些损失,但是安全。Mybatis默认是false。

    名称空间

    每个sql映射文件的要元素中,都需要指定一个名称空间,用以确保每个映射语句的id属性不会重复。如

    1. <mapper namespace="com.emerson.learning.mapping.user">

    在Java代码中引用某个sql映射时,使用的亦时含有名称空间的全路径。如

    1. session.update("com.emerson.learning.mapping.user.udpateUser", user);

    代码示例

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    4. <mapper namespace="com.emerson.learning.mapping.user">
    5. <sql id="columns">user_name, user_password, nick_name, email, user_type_id,
    6. is_valid, created_time</sql>
    7. <!-- 根据传入的Id值,到数据库中查询记录 -->
    8. <select id="getByID" parameterType="int" resultType="User">
    9. SELECT
    10. <include refid="columns"></include>
    11. FROM sys_user WHERE user_id = #{id}
    12. </select>
    13. <!-- 按用户名进行模糊查询 -->
    14. <select id="queryByName" parameterType="User" resultType="User">
    15. SELECT
    16. <include refid="columns"></include>
    17. FROM sys_user
    18. <where>
    19. <if test="userName != null">user_name like '%' #{userName} '%'</if>
    20. </where>
    21. </select>
    22. <!-- 创建新用户,并写入到数据表中 -->
    23. <!-- 写入新记录并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
    24. <insert id="insertUser" parameterType="User" useGeneratedKeys="true"
    25. keyProperty="userId">
    26. INSERT INTO sys_user(<include refid="columns"></include>)
    27. VALUES(#{userName},
    28. #{userPassword}, #{nickName}, #{userTypeId}, #{isValid},
    29. #{createdTime})
    30. </insert>
    31. <!-- 更新用户信息,并写回到数据表中 -->
    32. <update id="udpateUser" parameterType="User">
    33. UPDATE sys_user
    34. <set>
    35. <if test="userName != null">user_name = #{userName},</if>
    36. <if test="userPassword != null">user_password = #{userPassword},</if>
    37. <if test="nickName != null">nick_name = #{nickName},</if>
    38. <if test="userTypeId != null">user_type_id = #{userTypeId},</if>
    39. <if test="isValid != null">is_valid = #{isValid}</if>
    40. </set>
    41. WHERE user_id = #{userId}
    42. </update>
    43. <!-- 根据传入的Id值,删除单条记录 -->
    44. <delete id="deleteById" parameterType="int">
    45. DELETE FROM sys_user WHERE
    46. user_id = #{id}
    47. </delete>
    48. <!-- 根据传入的Id值列表,删除多条记录 -->
    49. <delete id="deleteBatch" parameterType="java.util.List">
    50. DELETE FROM sys_user WHERE user_id in
    51. <foreach collection="list" item="item" index="index" open="("
    52. close=")" separator=",">
    53. #{item}
    54. </foreach>
    55. </delete>
    56. </mapper>

    结束语

    至此,我们把Mybatis中sql映射文件的元素都已向大家介绍了一遍(除了ResultMap,这个留在后续的文章中详细讲解)。在下一篇文章《Mybatis系列(五)动态SQL》中,我们继续为大家讲解用于定义动态SQL的映射标签,静请期待!

Mybatis系列(四)映射文件的更多相关文章

  1. Mybatis系列全解(五):全网最全!详解Mybatis的Mapper映射文件

    封面:洛小汐 作者:潘潘 若不是生活所迫,谁愿意背负一身才华. 前言 上节我们介绍了 < Mybatis系列全解(四):全网最全!Mybatis配置文件 XML 全貌详解 >,内容很详细( ...

  2. MyBatis系列四 之 智能标签进行查询语句的拼接

    MyBatis系列四 之 智能标签进行查询语句的拼接 使用Foreach进行多条件查询 1.1 foreach使用数组进行多条件查询 在MyBatis的映射文件中进行如下配置 <!--根据数组进 ...

  3. Mybatis 系列2-配置文件

    [Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...

  4. Mybatis(二) SQL映射文件

    SQL映射文件 单条件查询 1. 在UserMapper接口添加抽象方法 //根据用户名模糊查询 List<User> getUserListByName(); 2. 在UserMappe ...

  5. Mybatis的XML映射文件(四)

    MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单.如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% ...

  6. mybatis Mapper XML 映射文件

    传送门:mybatis官方文档 Mapper XML 文件详解 一. 数据查询语句 1. select <select id="selectPerson" parameter ...

  7. Mybatis框架基于映射文件和配置文件的方式,实现增删改查,可以打印日志信息

    首先在lib下导入: 与打印日志信息有关的架包 log4j-1.2.16.jar mybatis架包:mybatis-3.1.1.jar 连接数据库的架包:mysql-connector-java-5 ...

  8. 初始MyBatis、SQL映射文件

    MyBatis入门 1.MyBatis前身是iBatis,是Apache的一个开源项目,2010年这个项目迁移到了Google Code,改名为MyBatis,2013年迁移到GitHub.是一个基于 ...

  9. MyBatis 的 XML 映射文件使用说明

    简介 文档参考地址:http://www.mybatis.org/mybatis-3/zh/index.html MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器 ...

  10. mybatis教程3(映射文件)

    MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单.如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% ...

随机推荐

  1. Java Thread类的yield()和join()的区别和用法

    yield: 解释它之前,先简述下,多线程的执行流程:多个线程并发请求执行时,由cpu决定优先执行哪一个,即使通过thread.setPriority(),设置了 线程的优先级,也不一定就是每次都先执 ...

  2. B. Clique Problem(贪心)

    题目链接: B. Clique Problem time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  3. RAD Studio Mobile Roadmap updated,XE5 will released on next month, Andriod will be supported.

    RAD Studio Mobile Roadmap updated   Embarcadero updated his RAD Studio Mobile Roadmap. This concern ...

  4. 无法打开包括文件:“iostream.h”

    把#include<iostream.h>改为:#include<iostream>using namespace std; #include<iostream.h> ...

  5. Discuz代码研究-编码规范

    Discuz中的编码规范很值得PHP开发人员借鉴.里面既介绍了编码时代码标记,注释,书写规则,命名原则等方面基础的内容,对代码的安全性,性能,兼容性,代码重用,数据库设计,数据库性能及优化作了阐述,这 ...

  6. 实体对象,List泛型 转换为DataTable

    /// <summary>        /// 实体对象转换DataTable        /// </summary>        /// <param name ...

  7. MAC OS X常用命令总结2

    1. dir:显示某个目录下的子目录与文件. 格式:dir [x:] [Path] [filename][ parameter] 参数解释: /a      显示所有文件夹与文件. /p     分页 ...

  8. LeetCode Max Stack

    原题链接在这里:https://leetcode.com/problems/max-stack/description/ 题目: Design a max stack that supports pu ...

  9. Linux性能评测工具之一:gprof篇介绍

    转:http://blog.csdn.net/stanjiang2010/article/details/5655143 这些天自己试着对项目作一些压力测试和性能优化,也对用过的测试工具作一些总结,并 ...

  10. rpm 软件包离线安装

    1. 插件安装(可选) yum install yum-plugin-downloadonly 2. 只下载不安装(perl 演示) yum install --downloadonly --down ...