Mybatis XML映射

来源:互联网 发布:北京市人口分布数据 编辑:程序博客网 时间:2024/06/04 01:27

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


select

查询语句是 MyBatis 中最常用的元素之一,光能把数据存到数据库中价值并不大,如果还能重新取出来才有用,多数应用也都是查询比修改要频繁。对每个插入、更新或删除操作,通常对应多个查询操作。这是 MyBatis 的基本原则之一,也是将焦点和努力放到查询和结果映射的原因。简单查询的 select 元素是非常简单的。比如:

<select id="selectPerson" parameterType="int" resultType="hashmap">  SELECT * FROM PERSON WHERE ID = #{id}</select>

这个语句被称作 selectPerson,接受一个 int(或 Integer)类型的参数,并返回一个 HashMap 类型的对象,其中的键是列名,值便是结果行中的对应值。

select 元素有很多属性允许你配置,来决定每条语句的作用细节。

<select  id="selectPerson"  parameterType="int"  parameterMap="deprecated"  resultType="hashmap"  resultMap="personResultMap"  flushCache="false"  useCache="true"  timeout="10000"  fetchSize="256"  statementType="PREPARED"  resultSetType="FORWARD_ONLY">
属性 描述 id 在命名空间中唯一的标识符,可以被用来引用这条语句。 parameterType 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。 parameterMap 这是引用外部 parameterMap 的已经被废弃的方法。使用内联参数映射和 resultType 从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。 resultMap 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同时使用。 flushCache 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false。 useCache 将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:对 select 元素为 true。 timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。 fetchSize 这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset(依赖驱动)。 statementType STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 resultSetType FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一个,默认值为 unset (依赖驱动)。 databaseId 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 resultOrdered 这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组了,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false。 resultSets 这个设置仅对多结果集的情况适用,它将列出语句执行后返回的结果集并每个结果集给一个名称,名称是逗号分隔的。

insert, update 和 delete

数据变更语句 insert,update 和 delete 的实现非常接近:

<insert  id="insertAuthor"  parameterType="domain.blog.Author"  flushCache="true"  statementType="PREPARED"  keyProperty=""  keyColumn=""  useGeneratedKeys=""  timeout="20"><update  id="updateAuthor"  parameterType="domain.blog.Author"  flushCache="true"  statementType="PREPARED"  timeout="20"><delete  id="deleteAuthor"  parameterType="domain.blog.Author"  flushCache="true"  statementType="PREPARED"  timeout="20">
属性 描述 id 命名空间中的唯一标识符,可被用来代表这条语句。 parameterType 将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。 parameterMap 这是引用外部 parameterMap 的已经被废弃的方法。使用内联参数映射和 parameterType 属性。 flushCache 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应插入、更新和删除语句)。 timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。 statementType STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 useGeneratedKeys (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。 keyProperty (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 keyColumn (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 databaseId 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前

示例:

<insert id="insertAuthor">  insert into Author (id,username,password,email,bio)  values (#{id},#{username},#{password},#{email},#{bio})</insert><update id="updateAuthor">  update Author set    username = #{username},    password = #{password},    email = #{email},    bio = #{bio}  where id = #{id}</update><delete id="deleteAuthor">  delete from Author where id = #{id}</delete><!-- useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上。便可自动生成主键的字段--><insert id="insertAuthor" useGeneratedKeys="true"    keyProperty="id">  insert into Author (username,password,email,bio)  values (#{username},#{password},#{email},#{bio})</insert><!--支持多行插入--><insert id="insertAuthor" useGeneratedKeys="true"    keyProperty="id">  insert into Author (username, password, email, bio) values  <foreach item="item" collection="list" separator=",">    (#{item.username}, #{item.password}, #{item.email}, #{item.bio})  </foreach></insert><!--生成一个随机 ID(最好不要这么做)--><insert id="insertAuthor">  <selectKey keyProperty="id" resultType="int" order="BEFORE">    select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1  </selectKey>  insert into Author    (id, username, password, email,bio, favourite_section)  values    (#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR})</insert>

sql

这个元素可以被用来定义可重用的 SQL 代码段,可以包含在其他语句中。它可以被静态地(在加载参数) 参数化. 不同的属性值通过包含的实例变化.

<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql><!--这个 SQL 片段可以被包含在其他语句中--><select id="selectUsers" resultType="map">  select    <include refid="userColumns"><property name="alias" value="t1"/></include>,    <include refid="userColumns"><property name="alias" value="t2"/></include>  from some_table t1    cross join some_table t2</select><!--属性值可以用于包含的refid属性或者包含的字句里面的属性值--><sql id="sometable">  ${prefix}Table</sql><sql id="someinclude">  from    <include refid="${include_target}"/></sql><select id="select" resultType="map">  select    field1, field2, field3  <include refid="someinclude">    <property name="prefix" value="Some"/>    <property name="include_target" value="sometable"/>  </include></select>

Result Maps

ResultMap 元素是 MyBatis 中最重要最强大的元素。它就是让你远离 90%的需要从结果 集中取出数据的 JDBC 代码的那个东西, 而且在一些情形下允许你做一些 JDBC 不支持的事 情。 事实上, 编写相似于对复杂语句联合映射这些等同的代码, 也许可以跨过上千行的代码。 ResultMap 的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们 的关系。

package com.someapp.model;public class User {  private int id;  private String username;  private String hashedPassword;  public int getId() {    return id;  }  public void setId(int id) {    this.id = id;  }  public String getUsername() {    return username;  }  public void setUsername(String username) {    this.username = username;  }  public String getHashedPassword() {    return hashedPassword;  }  public void setHashedPassword(String hashedPassword) {    this.hashedPassword = hashedPassword;  }}

这样的一个 JavaBean 可以被映射到结果集,就像映射到 HashMap 一样简单。

<select id="selectUsers" resultType="com.someapp.model.User">  select id, username, hashedPassword  from some_table  where id = #{id}</select>

注意:resultType=”实体类” 时,实体类中的属性名必须与数据库里的字段名相同,否则无法进行映射,当不想同时建议使用resultMap。

<resultMap id="userResultMap" type="User">  <id property="id" column="user_id" />  <result property="username" column="user_name"/>  <result property="password" column="hashed_password"/></resultMap>
<select id="selectUsers" resultMap="userResultMap">  select user_id, user_name, hashed_password  from some_table  where id = #{id}</select>

自动映射

当自动映射查询结果时,MyBatis会获取sql返回的列名并在java类中查找相同名字的属性(忽略大小写)。 这意味着如果Mybatis发现了ID列和id属性,Mybatis会将ID的值赋给id。

通常数据库列使用大写单词命名,单词间用下划线分隔;而java属性一般遵循驼峰命名法。 为了在这两种命名方式之间启用自动映射,需要将 mapUnderscoreToCamelCase设置为true。

自动映射甚至在特定的result map下也能工作。在这种情况下,对于每一个result map,所有的ResultSet提供的列, 如果没有被手工映射,则将被自动映射。自动映射处理完毕后手工映射才会被处理。 在接下来的例子中, id 和 userName列将被自动映射, hashed_password 列将根据配置映射。

<resultMap id="userResultMap" type="User">  <result property="password" column="hashed_password"/></resultMap><select id="selectUsers" resultMap="userResultMap">  select    user_id             as "id",    user_name           as "userName",    hashed_password  from some_table  where id = #{id}</select>

自动映射等级

  • NONE : 禁用自动映射。仅设置手动映射属性。
  • PARTIAL : 将自动映射结果除了那些有内部定义内嵌结果映射的(joins).
  • FULL : 自动映射所有。

通过添加autoMapping属性可以忽略自动映射等级配置,你可以启用或者禁用自动映射指定的ResultMap。

<resultMap id="userResultMap" type="User" autoMapping="false">  <result property="password" column="hashed_password"/></resultMap>

缓存

自定义缓存

MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis 3 中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。

默认情况下是没有开启缓存的,除了局部的 session 缓存,可以增强变现而且处理循环 依赖也是必须的。要开启二级缓存,你需要在你的 SQL 映射文件中添加一行:< cache/>。作用如下:

  • 映射语句文件中的所有 select 语句将会被缓存。
  • 映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
  • 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
  • 根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
  • 缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
    缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
  • 缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
<!--eviction : 这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。--><!--flushInterval(刷新间隔) : 可以被设置为任意的正整数,而且它们代表一个合理的毫秒 形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。--><!--size(引用数目) : 可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。--><!--readOnly(只读) : 属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。--><cache  eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>

可用的收回策略有:

  • LRU : 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO : 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT : 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK : 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

使用自定义缓存

除了这些自定义缓存的方式, 你也可以通过实现你自己的缓存或为其他第三方缓存方案 创建适配器来完全覆盖缓存行为。

<cache type="com.domain.something.MyCustomCache"/>

这个示 例展 示了 如何 使用 一个 自定义 的缓 存实 现。type 属 性指 定的 类必 须实现 org.mybatis.cache.Cache 接口。这个接口是 MyBatis 框架中很多复杂的接口之一,但是简单 给定它做什么就行。

public interface Cache {  String getId();  int getSize();  void putObject(Object key, Object value);  Object getObject(Object key);  boolean hasKey(Object key);  Object removeObject(Object key);  void clear();}

要配置你的缓存, 简单和公有的 JavaBeans 属性来配置你的缓存实现, 而且是通过 cache 元素来传递属性, 比如, 下面代码会在你的缓存实现中调用一个称为 “setCacheFile(String file)” 的方法:

<cache type="com.domain.something.MyCustomCache">  <property name="cacheFile" value="/tmp/my-custom-cache.tmp"/></cache>

记得缓存配置和缓存实例是绑定在 SQL 映射文件的命名空间是很重要的。因此,所有 在相同命名空间的语句正如绑定的缓存一样。 语句可以修改和缓存交互的方式, 或在语句的 语句的基础上使用两种简单的属性来完全排除它们。默认情况下,语句可以这样来配置:

select ... flushCache="false" useCache="true"/><insert ... flushCache="true"/><update ... flushCache="true"/><delete ... flushCache="true"/>

参照缓存

特殊命名空间的唯一缓存会被使用或者刷新相同命名空间内 的语句。也许将来的某个时候,你会想在命名空间中共享相同的缓存配置和实例。在这样的 情况下你可以使用 cache-ref 元素来引用另外一个缓存。

<cache-ref namespace="com.someone.application.data.SomeMapper"/>
0 0
原创粉丝点击