mybatis XML映射文件

太过爱你忘了你带给我的痛 2023-02-18 15:20 104阅读 0赞

mybatis XML映射文件

  • 1、XML 映射文件
    • 1.1 XML映射器
    • 1.2 select
      • 1.2.1 Select 元素的属性
    • 1.3 insert,update和delete
      • 1.3.1 Insert, Update, Delete 元素的属性
      • 1.3.2 selectKey 元素描述如下:
    • 1.4 sql
    • 1.5 参数
    • 1.6 字符串替换
    • 1.7 结果映射
    • 1,8 高级结果映射
      • 1.8.1 结果映射(resultMap)
      • 1.8.2 id & result
    • 1.9 支持的JDBC类型
    • 1.10 构造方法
    • 1.11 关联
    • 1.12 关联的嵌套select查询
    • 1.13 关联的嵌套结果映射
    • 1.14 关联的多结果集(ResultSet)

原文地址:mybatis官方API:mybatis

1、XML 映射文件

1.1 XML映射器

SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

  • cache – 该命名空间的缓存配置。
  • cache-ref – 引用其它命名空间的缓存配置。
  • resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
  • parameterMap – 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。
  • sql – 可被其它语句引用的可重用语句块。
  • insert – 映射插入语句。
  • update – 映射更新语句。
  • delete – 映射删除语句。
  • select – 映射查询语句。

1.2 select

MyBatis 的基本原则之一是:在每个插入、更新或删除操作之间,通常会执行多个查询操作。

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

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

select 元素允许你配置很多属性来配置每条语句的行为细节。

  1. <select id="selectPerson" parameterType="int" parameterMap="deprecated" resultType="hashmap" resultMap="personResultMap" flushCache="false" useCache="true" timeout="10" fetchSize="256" statementType="PREPARED" resultSetType="FORWARD_ONLY">

1.2.1 Select 元素的属性

format_png

1.3 insert,update和delete

  1. <insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" keyColumn="" useGeneratedKeys="" timeout="20">
  2. <update id="updateAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20">
  3. <delete id="deleteAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20">

1.3.1 Insert, Update, Delete 元素的属性

format_png 1

  1. <insert id="insertAuthor">
  2. insert into Author (id,username,password,email,bio)
  3. values (#{id},#{username},#{password},#{email},#{bio})
  4. </insert>
  5. <update id="updateAuthor">
  6. update Author set
  7. username = #{username},
  8. password = #{password},
  9. email = #{email},
  10. bio = #{bio}
  11. where id = #{id}
  12. </update>
  13. <delete id="deleteAuthor">
  14. delete from Author where id = #{id}
  15. </delete>

首先,如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置为目标属性就 OK 了。例如,如果上面的 Author 表已经在 id 列上使用了自动生成,那么语句可以修改为:

  1. <insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
  2. insert into Author (username,password,email,bio)
  3. values (#{username},#{password},#{email},#{bio})
  4. </insert>

如果你的数据库还支持多行插入, 你也可以传入一个 Author 数组或集合,并返回自动生成的主键。

  1. <insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
  2. insert into Author (username, password, email, bio) values
  3. <foreach item="item" collection="list" separator=",">
  4. (#{item.username}, #{item.password}, #{item.email}, #{item.bio})
  5. </foreach>
  6. </insert>

1.3.2 selectKey 元素描述如下:

  1. <selectKey keyProperty="id" resultType="int" order="BEFORE" statementType="PREPARED">

format_png 2

1.4 sql

这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。 参数可以静态地(在加载的时候)确定下来,并且可以在不同的 include 元素中定义不同的参数值。比如:

  1. <sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>

这个 SQL 片段可以在其它语句中使用,例如:

  1. <select id="selectUsers" resultType="map">
  2. select
  3. <include refid="userColumns"><property name="alias" value="t1"/></include>,
  4. <include refid="userColumns"><property name="alias" value="t2"/></include>
  5. from some_table t1
  6. cross join some_table t2
  7. </select>

也可以在 include 元素的 refid 属性或内部语句中使用属性值,例如:

  1. <sql id="sometable">
  2. ${prefix}Table
  3. </sql>
  4. <sql id="someinclude">
  5. from
  6. <include refid="${include_target}"/>
  7. </sql>
  8. <select id="select" resultType="map">
  9. select
  10. field1, field2, field3
  11. <include refid="someinclude">
  12. <property name="prefix" value="Some"/>
  13. <property name="include_target" value="sometable"/>
  14. </include>
  15. </select>

1.5 参数

  1. <insert id="insertUser" parameterType="User">
  2. insert into users (id, username, password)
  3. values (#{id}, #{username}, #{password})
  4. </insert>

如果 User 类型的参数对象传递到了语句中,会查找 id、username 和 password 属性,然后将它们的值传入预处理语句的参数中。

首先,和 MyBatis 的其它部分一样,参数也可以指定一个特殊的数据类型。
#{property,javaType=int,jdbcType=NUMERIC}
MyBatis 的其它部分一样,几乎总是可以根据参数对象的类型确定 javaType,除非该对象是一个 HashMap。这个时候,你需要显式指定 javaType 来确保正确的类型处理器(TypeHandler)被使用。

进一步地自定义类型处理方式,可以指定一个特殊的类型处理器类(或别名),比如:
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

对于数值类型,还可以设置 numericScale 指定小数点后保留的位数。
#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

mode 属性允许你指定 IN,OUT 或 INOUT 参数。如果参数的 mode 为 OUT 或 INOUT,将会修改参数对象的属性值,以便作为输出参数返回。 如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 引用来将结果集 ResultMap 映射到参数的类型上。要注意这里的 javaType 属性是可选的,如果留空并且 jdbcType 是 CURSOR,它会被自动地被设为 ResultMap。
#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

MyBatis 也支持很多高级的数据类型,比如结构体(structs),但是当使用 out 参数时,你必须显式设置类型的名称。
#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

1.6 字符串替换

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句,这时候你可以:
ORDER BY ${columnName}

当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。 举个例子,如果你想 select 一个表任意一列的数据时,不需要这样写:

  1. @Select("select * from user where id = #{id}")
  2. User findById(@Param("id") long id);
  3. @Select("select * from user where name = #{name}")
  4. User findByName(@Param("name") String name);
  5. @Select("select * from user where email = #{email}")
  6. User findByEmail(@Param("email") String email);
  7. // 其它的 "findByXxx" 方法

而是可以只写这样一个方法:

  1. @Select("select * from user where ${column} = #{value}")
  2. User findByColumn(@Param("column") String column, @Param("value") String value);

其中 ${column} 会被直接替换,而 #{value} 会使用 ? 预处理。

  1. User userOfId1 = userMapper.findByColumn("id", 1L);
  2. User userOfNameKid = userMapper.findByColumn("name", "kid");
  3. User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");

用这种方式接受用户的输入,并用作语句参数是不安全的,会导致潜在的 SQL 注入攻击。因此,要么不允许用户输入这些字段,要么自行转义并检验这些参数。

1.7 结果映射

ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

  1. <select id="selectUsers" resultType="map">
  2. select id, username, hashedPassword
  3. from some_table
  4. where id = #{id}
  5. </select>

上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。
程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为领域模型。MyBatis 对两者都提供了支持。看看下面这个 JavaBean:

  1. package com.someapp.model;
  2. public class User {
  3. private int id;
  4. private String username;
  5. private String hashedPassword;
  6. //省略Set get方法

基于 JavaBean 的规范,上面这个类有 3 个属性:id,username 和 hashedPassword。这些属性会对应到 select 语句中的列名。

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

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

类型别名是你的好帮手。使用它们,你就可以不用输入类的全限定名了。比如:

  1. <!-- mybatis-config.xml 中 -->
  2. <typeAlias type="com.someapp.model.User" alias="User"/>
  3. <!-- SQL 映射 XML 中 -->
  4. <select id="selectUsers" resultType="User">
  5. select id, username, hashedPassword
  6. from some_table
  7. where id = #{id}
  8. </select>

MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。比如:

  1. <select id="selectUsers" resultType="User">
  2. select
  3. user_id as "id",
  4. user_name as "userName",
  5. hashed_password as "hashedPassword"
  6. from some_table
  7. where id = #{id}
  8. </select>

使用外部的 resultMap:

  1. <resultMap id="userResultMap" type="User">
  2. <id property="id" column="user_id" />
  3. <result property="username" column="user_name"/>
  4. <result property="password" column="hashed_password"/>
  5. </resultMap>

然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如:

  1. <select id="selectUsers" resultMap="userResultMap">
  2. select user_id, user_name, hashed_password
  3. from some_table
  4. where id = #{id}
  5. </select>

1,8 高级结果映射

  1. <!-- 非常复杂的结果映射 -->
  2. <resultMap id="detailedBlogResultMap" type="Blog">
  3. <constructor>
  4. <idArg column="blog_id" javaType="int"/>
  5. </constructor>
  6. <result property="title" column="blog_title"/>
  7. <association property="author" javaType="Author">
  8. <id property="id" column="author_id"/>
  9. <result property="username" column="author_username"/>
  10. <result property="password" column="author_password"/>
  11. <result property="email" column="author_email"/>
  12. <result property="bio" column="author_bio"/>
  13. <result property="favouriteSection" column="author_favourite_section"/>
  14. </association>
  15. <collection property="posts" ofType="Post">
  16. <id property="id" column="post_id"/>
  17. <result property="subject" column="post_subject"/>
  18. <association property="author" javaType="Author"/>
  19. <collection property="comments" ofType="Comment">
  20. <id property="id" column="comment_id"/>
  21. </collection>
  22. <collection property="tags" ofType="Tag" >
  23. <id property="id" column="tag_id"/>
  24. </collection>
  25. <discriminator javaType="int" column="draft">
  26. <case value="1" resultType="DraftPost"/>
  27. </discriminator>
  28. </collection>
  29. </resultMap>

1.8.1 结果映射(resultMap)

  • constructor - 用于在实例化类时,注入结果到构造方法中

    • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
    • arg - 将被注入到构造方法的一个普通结果
  • id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
  • result – 注入到字段或 JavaBean 属性的普通结果
  • association – 一个复杂类型的关联;许多结果将包装成这种类型

    • 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
  • collection – 一个复杂类型的集合

    • 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
  • discriminator – 使用结果值来决定使用哪个 resultMap

    • case – 基于某些值的结果映射

      • 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射

ResultMap 的属性列表:
format_png 3

1.8.2 id & result

  1. <id property="id" column="post_id"/>
  2. <result property="subject" column="post_subject"/>

这些元素是结果映射的基础。id 和 result 元素都将一个列的值映射到一个简单数据类型(String, int, double, Date 等)的属性或字段。

这两者之间的唯一不同是,id 元素对应的属性会被标记为对象的标识符,在比较对象实例时使用。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。

Id 和 Result 的属性
format_png 4

1.9 支持的JDBC类型

MyBatis 通过内置的 jdbcType 枚举类型支持下面的 JDBC 类型。
format_png 5

1.10 构造方法

通过修改对象属性的方式,可以满足大多数的数据传输对象(Data Transfer Object, DTO)以及绝大部分领域模型的要求。但有些情况下你想使用不可变类。 一般来说,很少改变或基本不变的包含引用或数据的表,很适合使用不可变类。 构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。MyBatis 也支持私有属性和私有 JavaBean 属性来完成注入,但有一些人更青睐于通过构造方法进行注入。 constructor 元素就是为此而生的。

看看下面这个构造方法:

  1. public class User {
  2. //...
  3. public User(Integer id, String username, int age) {
  4. //...
  5. }
  6. //...
  7. }

为了将结果注入构造方法,MyBatis 需要通过某种方式定位相应的构造方法。 在下面的例子中,MyBatis 搜索一个声明了三个形参的构造方法,参数类型以 java.lang.Integer, java.lang.String 和 int 的顺序给出。

  1. <constructor>
  2. <idArg column="id" javaType="int"/>
  3. <arg column="username" javaType="String"/>
  4. <arg column="age" javaType="_int"/>
  5. </constructor>

当你在处理一个带有多个形参的构造方法时,很容易搞乱 arg 元素的顺序。 从版本 3.4.3 开始,可以在指定参数名称的前提下,以任意顺序编写 arg 元素。 为了通过名称来引用构造方法参数,你可以添加 @Param 注解,或者使用 ‘-parameters’ 编译选项并启用 useActualParamName 选项(默认开启)来编译项目。下面是一个等价的例子,尽管函数签名中第二和第三个形参的顺序与 constructor 元素中参数声明的顺序不匹配。

  1. <constructor>
  2. <idArg column="id" javaType="int" name="id" />
  3. <arg column="age" javaType="_int" name="age" />
  4. <arg column="username" javaType="String" name="username" />
  5. </constructor>

如果存在名称和类型相同的属性,那么可以省略 javaType 。

剩余的属性和规则和普通的 id 和 result 元素是一样的。
format_png 6

1.11 关联

  1. <association property="author" column="blog_author_id" javaType="Author">
  2. <id property="id" column="author_id"/>
  3. <result property="username" column="author_username"/>
  4. </association>

关联(association)元素处理“有一个”类型的关系。 比如,在我们的示例中,一个博客有一个用户。关联结果映射和其它类型的映射工作方式差不多。 你需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。

关联的不同之处是,你需要告诉 MyBatis 如何加载关联。MyBatis 有两种不同的方式加载关联:

  • 嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
  • 嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。
    首先,先让我们来看看这个元素的属性。你将会发现,和普通的结果映射相比,它只在 select 和 resultMap 属性上有所不同。

format_png 7

1.12 关联的嵌套select查询

format_png 8

  1. <resultMap id="blogResult" type="Blog">
  2. <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
  3. </resultMap>
  4. <select id="selectBlog" resultMap="blogResult">
  5. SELECT * FROM BLOG WHERE ID = #{id}
  6. </select>
  7. <select id="selectAuthor" resultType="Author">
  8. SELECT * FROM AUTHOR WHERE ID = #{id}
  9. </select>

1.13 关联的嵌套结果映射

format_png 9

  1. <select id="selectBlog" resultMap="blogResult">
  2. select
  3. B.id as blog_id,
  4. B.title as blog_title,
  5. B.author_id as blog_author_id,
  6. A.id as author_id,
  7. A.username as author_username,
  8. A.password as author_password,
  9. A.email as author_email,
  10. A.bio as author_bio
  11. from Blog B left outer join Author A on B.author_id = A.id
  12. where B.id = #{id}
  13. </select>

注意查询中的连接,以及为确保结果能够拥有唯一且清晰的名字,我们设置的别名。 这使得进行映射非常简单。现在我们可以映射这个结果:

  1. <resultMap id="blogResult" type="Blog">
  2. <id property="id" column="blog_id" />
  3. <result property="title" column="blog_title"/>
  4. <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
  5. </resultMap>
  6. <resultMap id="authorResult" type="Author">
  7. <id property="id" column="author_id"/>
  8. <result property="username" column="author_username"/>
  9. <result property="password" column="author_password"/>
  10. <result property="email" column="author_email"/>
  11. <result property="bio" column="author_bio"/>
  12. </resultMap>

1.14 关联的多结果集(ResultSet)

format_png 10

发表评论

表情:
评论列表 (有 0 条评论,104人围观)

还没有评论,来说两句吧...

相关阅读

    相关 MybatisXML映射文件

    MyBatis 针对 SQL 构建,真正强大在于它的映射语句。 SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序): cache – 给定命名空间的缓存配