`

Mybatis映射的XML文件

阅读更多

Mybatis映射的XML文件

 

MyBatis真正的力量是在映射语句中。这里是奇迹发生的地方。对于所有的力量,SQL映射的XML文件是相当的简单。当然如果你将它们和对等功能的JDBC代码来比较,你会发现映射文件节省了大约95%的代码量。MyBatis的构建就是聚焦于SQL的,使其远离于普通的方式。

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

 cache - 配置给定命名空间的缓存。

 cache-ref – 从其他命名空间引用缓存配置。

 resultMap – 最复杂,也是最有力量的元素,用来描述如何从数据库结果集中来加载你的对象。

 parameterMap – 已经被废弃了!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。这里不会记录。

 sql – 可以重用的SQL块,也可以被其他语句引用。

 insert – 映射插入语句

 update – 映射更新语句

 delete – 映射删除语句

 select – 映射查询语句

下一部分将从语句本身开始来描述每个元素的细节。

 

select

查询语句是使用MyBatis时最常用的元素之一。直到你从数据库取出数据时才会发现将数据存在数据库中是多么的有价值,所以许多应用程序的查询操作要比更改数据操作多的多。对于每次插入,更新或删除,那也会有很多的查询。这是MyBatis的一个基本原则,也是将重心和努力放到查询和结果映射的原因。对简单类别的查询元素是非常简单的。比如:

<select id=”selectPerson” parameterType=”int” resultType=”hashmap”>

SELECT * FROM PERSON WHERE ID = #{id}

</select>

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

注意参数注释:

#{id}

这就告诉MyBatis创建一个PreparedStatement(预处理语句)参数。使用JDBC,这样的一个参数在SQL中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:

// 相似的JDBC代码,不是MyBatis的

String selectPerson = “SELECT * FROM PERSON WHERE ID=?”;

PreparedStatement ps = conn.prepareStatement(selectPerson);

ps.setInt(1,id);

当然,这需要很多单独的JDBC的代码来提取结果并将它们映射到对象实例中,这就是MyBatis节省你时间的地方。我们需要深入了解参数和结果映射。那些细节部分我们下面来了解。

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”

>

 

 

insert,update,delete

数据修改语句insert,update和delete在它们的实现中非常相似:

<insert

id="insertAuthor"

parameterType="domain.blog.Author"

flushCache="true"

statementType="PREPARED"

keyProperty=""

useGeneratedKeys=""

timeout="20000">

<update

id="insertAuthor"

parameterType="domain.blog.Author"

flushCache="true"

statementType="PREPARED"

timeout="20000">

<delete

id="insertAuthor"

parameterType="domain.blog.Author"

flushCache="true"

statementType="PREPARED"

timeout="20000">

 

 

下面就是insert,update和delete语句的示例:

<insert id="insertAuthor" parameterType="domain.blog.Author">

insert into Author (id,username,password,email,bio)

values (#{id},#{username},#{password},#{email},#{bio})

</insert>

<update id="updateAuthor" parameterType="domain.blog.Author">

update Author set

username = #{username},

password = #{password},

email = #{email},

bio = #{bio}

where id = #{id}

</update>

<delete id="deleteAuthor” parameterType="int">

delete from Author where id = #{id}

</delete>

如前所述,插入语句有一点多,它有一些属性和子元素用来处理主键的生成。

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

<insert id="insertAuthor" parameterType="domain.blog.Author"

useGeneratedKeys=”true” keyProperty=”id”>

insert into Author (username,password,email,bio)

values (#{username},#{password},#{email},#{bio})

</insert>

 

sql

这个元素可以被用来定义可重用的SQL代码段,可以包含在其他语句中。比如:

<sql id=”userColumns”> id,username,password </sql>

这个SQL片段可以被包含在其他语句中,例如:

<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>

select <include refid=”userColumns”/>

from some_table

where id = #{id}

</select>

 

Parameters

在之前的语句中,你已经看到了一些简单参数的示例。在MyBatis中参数是非常强大的元素。对于简单的做法,大概90%的情况,是不用太多的,比如:

<select id=”selectUsers” parameterType=”int” resultType=”User”>

select id, username, password

from users

where id = #{id}

</select>

上面的这个示例说明了一个非常简单的命名参数映射。参数类型被设置为“int”,因此这个参数可以被设置成任何内容。原生的类型或简单数据类型,比如整型和没有相关属性的字符串,因此它会完全用参数来替代。然而,如果你传递了一个复杂的对象,那么MyBatis的处理方式就会有一点不同。比如:

<insert id=”insertUser” parameterType=”User” >

insert into users (id, username, password)

values (#{id}, #{username}, #{password})

</insert>

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

这点对于传递参数到语句中非常好。但是对于参数映射也有一些其他的特性。

首先,像MyBatis的其他部分,参数可以指定一个确定的数据类型。

#{property,javaType=int,jdbcType=NUMERIC}

像MyBatis的剩余部分,javaType通常可以从参数对象中来确定,除非对象是一个HashMap。那么javaType应该被确定来保证使用正确类型处理器。

注意:如果null被当作值来传递,对于所有可能为空的列,JDBC Type是需要的。也可以通过阅读PreparedStatement. setNull()方法的JavaDocs文档来研究它。

为了以后自定义类型处理器,你可以指定一个确定的类型处理器类(或别名),比如:

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

尽管它看起来繁琐,但是实际上是你很少设置它们其中之一。

对于数值类型,对于决定有多少数字是相关的,有一个数值范围。

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

最后,mode属性允许你指定IN,OUT或INOUT参数。如果参数为OUT或INOUT,参数对象属性的真实值将会被改变,就像你期望你需要你个输出参数。如果mode为OUT(或INOUT),而且jdbcType为CURSOR(也就是Oracle的REFCURSOR),你必须指定一个resultMap来映射结果集到参数类型。要注意这里的javaType属性是可选的,如果左边的空白是jdbcType的CURSOR类型,它会自动地被设置为结果集。

#{department,

mode=OUT,

jdbcType=CURSOR,

javaType=ResultSet,

resultMap=departmentResultMap}

MyBatis也支持很多高级的数据类型,比如结构体,但是当注册out参数时你必须告诉语句类型名称。比如(再次提示,在实际中不要像这样换行):

#{middleInitial,

mode=OUT,

jdbcType=STRUCT,

jdbcTypeName=MY_TYPE,

resultMap=departmentResultMap}

尽管所有这些强大的选项很多时候你只简单指定属性名,MyBatis会自己计算剩余的。最多的情况是你为jdbcType指定可能为空的列名。

#{firstName}

#{middleInitial,jdbcType=VARCHAR}

#{lastName}

字符串替换

默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置安全的值(比如?)。这样做很安全,很迅速,也是首选的做法,有时你只是想直接在SQL语句中插入一个不改变的字符串。比如,像ORDER BY,你可以这样来使用:

ORDER BY ${columnName}

这里MyBatis不会修改或转义字符串。

重要:接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。

resultMap

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

你已经看到简单映射语句的示例了,但没有明确的resultMap。比如:

<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>

select id, username, hashedPassword

from some_table

where id = #{id}

</select>

这样一个语句简单作用于所有列被自动映射到HashMap的键上,这由resultType属性指定。这在很多情况下是有用的,但是HashMap不能很好描述一个领域模型。那样你的应用程序将会使用JavaBeans或POJOs(Plain Old Java Objects,普通Java对象)来作为领域模型。MyBatis对两者都支持。看看下面这个JavaBean:

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的规范,上面这个类有3个属性:id,username和hashedPassword。这些在select语句中会精确匹配到列名。

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

<select id=”selectUsers” parameterType=”int”

resultType=”com.someapp.model.User”>

select id, username, hashedPassword

from some_table

where id = #{id}

</select>

要记住类型别名是你的伙伴。使用它们你可以不用输入类的全路径。比如:

<!-- 在XML配置文件中-->

<typeAlias type=”com.someapp.model.User” alias=”User”/>

<!-- 在SQL映射的XML文件中-->

<select id=”selectUsers” parameterType=”int”

resultType=”User”>

select id, username, hashedPassword

from some_table

where id = #{id}

</select>

这些情况下,MyBatis会在幕后自动创建一个ResultMap,基于属性名来映射列到JavaBean的属性上。如果列名没有精确匹配,你可以在列名上使用select字句的别名(一个标准的SQL特性)来匹配标签。比如:

<select id=”selectUsers” parameterType=”int” resultType=”User”>

select

user_id as “id”,

user_name as “userName”,

hashed_password as “hashedPassword”

from some_table

 

where id = #{id}

</select>

ResultMap最优秀的地方你已经了解了很多了,但是你还没有真正的看到一个。这些简单的示例不需要比你看到的更多东西。只是出于示例的原因,让我们来看看最后一个示例中外部的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>

引用它的语句使用resultMap属性就行了(注意我们去掉了resultType属性)。比如:

<select id=”selectUsers” parameterType=”int”

resultMap=”userResultMap”>

select user_id, user_name, hashed_password

from some_table

where id = #{id}

</select>

如果世界总是这么简单就好了。

高级结果映射

MyBatis创建的一个想法:数据库不用永远是你想要的或需要它们是什么样的。而我们最喜欢的数据库最好是第三范式或BCNF范式,但它们有时不是。如果可能有一个单独的数据库映射,所有应用程序都可以使用它,这是非常好的,但有时也不是。结果映射就是MyBatis提供处理这个问题的答案。

比如,我们如何映射下面这个语句?

<!-- 非常复杂的语句 -->

<select id="selectBlogDetails" parameterType="int"

resultMap="detailedBlogResultMap">

select

B.id as blog_id,

B.title as blog_title,

B.author_id as blog_author_id,

A.id as author_id,

A.username as author_username,

A.password as author_password,

A.email as author_email,

A.bio as author_bio,

A.favourite_section as author_favourite_section,

P.id as post_id,

P.blog_id as post_blog_id,

P.author_id as post_author_id,

P.created_on as post_created_on,

P.section as post_section,

P.subject as post_subject,

P.draft as draft,

P.body as post_body,

C.id as comment_id,

C.post_id as comment_post_id,

C.name as comment_name,

C.comment as comment_text,

T.id as tag_id,

T.name as tag_name

from Blog B

left outer join Author A on B.author_id = A.id

left outer join Post P on B.id = P.blog_id

left outer join Comment C on P.id = C.post_id

left outer join Post_Tag PT on PT.post_id = P.id

left outer join Tag T on PT.tag_id = T.id

where B.id = #{id}

</select>

你可能想把它映射到一个智能的对象模型,包含一个作者写的博客,有很多的博文,每篇博文有零条或多条的评论和标签。下面是一个完整的复杂结果映射例子(假设作者,博客,博文,评论和标签都是类型的别名)。我们来看看,但是不用紧张,我们会一步一步来说明。当天最初它看起来令人生畏,但实际上非常简单。

<!-- 非常复杂的结果映射 -->

<resultMap id="detailedBlogResultMap" type="Blog">

<constructor>

<idArg column="blog_id" javaType="int"/>

</constructor>

<result property="title" column="blog_title"/>

<association property="author" column="blog_author_id" javaType=" Author">

<id property="id" column="author_id"/>

<result property="username" column="author_username"/>

<result property="password" column="author_password"/>

<result property="email" column="author_email"/>

<result property="bio" column="author_bio"/>

<result property="favouriteSection" column="author_favourite_section"/>

</association>

<collection property="posts" ofType="Post">

<id property="id" column="post_id"/>

<result property="subject" column="post_subject"/>

<association property="author" column="post_author_id" javaType="Author"/>

<collection property="comments" column="post_id" ofType=" Comment">

<id property="id" column="comment_id"/>

</collection>

<collection property="tags" column="post_id" ofType=" Tag" >

<id property="id" column="tag_id"/>

</collection>

<discriminator javaType="int" column="draft">

<case value="1" resultType="DraftPost"/>

</discriminator>

</collection>

</resultMap>

resultMap元素有很多子元素和一个值得讨论的结构。下面是resultMap元素的概念视图

resultMap

 constructor – 类在实例化时,用来注入结果到构造方法中

 idArg – ID参数;标记结果作为ID可以帮助提高整体效能

 arg – 注入到构造方法的一个普通结果

 id – 一个ID结果;标记结果作为ID可以帮助提高整体效能

 result – 注入到字段或JavaBean属性的普通结果

 association – 一个复杂的类型关联;许多结果将包成这种类型

 嵌入结果映射 – 结果映射自身的关联,或者参考一个

 collection – 复杂类型的集

 嵌入结果映射 – 结果映射自身的集,或者参考一个

 discriminator – 使用结果值来决定使用哪个结果映射

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

 嵌入结果映射 – 这种情形结果也映射它本身,因此可以包含很多相同的元素,或者它可以参照一个外部的结果映射。

最佳实践:通常逐步建立结果映射。单元测试的真正帮助在这里。如果你尝试创建一次创建一个向上面示例那样的巨大的结果映射,那么可能会有错误而且很难去控制它来工作。开始简单一些,一步一步的发展。而且要进行单元测试!使用该框架的缺点是它们有时是黑盒(是否可见源代码)。你确定你实现想要的行为的最好选择是编写单元测试。它也可以你帮助得到提交时的错误。

下面一部分将详细说明每个元素。

分享到:
评论

相关推荐

    mybatis映射文件xml+bean+dao自动构建

    本文将深入探讨“mybatis映射文件xml+bean+dao自动构建”的主题,以及如何利用代码生成工具来提高开发效率。 首先,让我们理解一下标题中的各个组成部分: 1. **MyBatis映射文件(XML)**:MyBatis的核心之一是XML...

    mybatis映射XML文件详解及实例

    本文将深入解析MyBatis映射XML文件的各个组成部分,并通过实例来帮助理解其工作原理。 首先,映射XML文件的根元素是`&lt;mapper&gt;`,它包含了一个`namespace`属性,该属性的值通常与对应的Java接口全限定名一致,用于...

    mybatis xml文件自动生成

    "mybatis xml文件自动生成"是开发过程中的一个重要环节,它可以帮助开发者提高效率,减少手动编写XML映射文件和对应的POJO(Plain Old Java Object)类的工作量。 MyBatis的Mapper文件是其核心组成部分之一,它包含...

    mybatis映射文件自动生成工具

    MyBatis映射文件自动生成工具是一款高效实用的开发辅助软件,主要针对MyBatis框架下的XML映射文件编写工作。这款工具极大地提高了开发效率,减少了手动编写XML映射文件的繁琐过程。通过在`generator.xml`配置文件中...

    mybatis映射文件.xml

    mybatis映射文件.xml

    mybatis映射生成工具

    通过配置数据库信息,开发者可以快速生成所需的DAO、Bean和XML文件,使开发工作更加顺畅。对于大型项目或者团队协作来说,这样的工具能够有效降低出错率,提高开发效率,是MyBatis开发中的得力助手。

    mybatis导出xml文件(只支持mysql数据库)

    总结来说,"mybatis导出xml文件(只支持mysql数据库)"涉及到MyBatis框架中的一种自动化工具,它能帮助开发者快速生成针对MySQL数据库的MyBatis XML映射文件,从而简化开发流程,提高工作效率。这种工具通常基于数据库...

    mybatis_xml插件

    总之,MyBatis_XML插件是Java开发中针对MyBatis框架的一个强大辅助工具,它简化了XML文件的管理和查找,提升了开发人员的工作效率,是MyBatis开发不可或缺的一部分。通过熟练掌握并运用这个插件,可以大大提高项目的...

    maven生成mybatis映射文件

    通过以上步骤,我们可以利用Maven与MyBatis Generator的结合,实现自动化生成MyBatis映射文件,提升开发效率,减少手动编写重复代码的工作量。记得在实际应用中根据项目特点进行适当的调整和优化。

    自动生成mybatis映射文件工具

    自动生成mybatis映射文件工具; 步骤: 1》打开generatorConfig.xml文件,配置自己的数据库连接参数 2》配置实体类、mapper映射文件、mapper接口 3》:回到根目录,按住Shif+鼠标右键(即在当前目录打开命令行),...

    关于MyBatis找不到映射文件的问题

    在pom.xml文件中,我们需要添加以下配置:&lt;build&gt; &lt;resources&gt; &lt;resource&gt; &lt;directory&gt;src/main/java&lt;/directory&gt; &lt;includes&gt; &lt;include&gt;/*.properties&lt;/include&gt; &lt;include&gt;/*.xml&lt;/include&gt; &lt;/includes&gt; &lt;filtering&gt;...

    mybatis_xml关联插件

    在常规开发中,当我们在XML文件中定义了一个SQL映射,需要找到对应的Java方法来理解其逻辑。而通过此插件,开发者可以直接查看到XML文件中的方法实现类,省去了在代码库中手动搜索的时间,提高了开发效率。 安装...

    spring和Mybatis的xml配置文件提示约束包

    "spring和Mybatis的xml配置文件提示约束包"这个主题,主要是关于在XML配置文件中使用的DTD(Document Type Definition)文档类型定义,它为XML文件提供了结构约束和语法规范。 DTD是一种元语言,用于定义XML文档的...

    mybatis映射文件生成工具

    MyBatis映射文件生成工具是一款实用的开发辅助软件,主要功能是自动生成MyBatis的映射文件(Mapper XML文件),从而极大地提高了开发效率,减轻了开发人员手动编写SQL和映射语句的工作负担。在数据库表结构发生变化...

    自动生成MyBatis的实体类、实体映射XML文件

    MyBatis的使用通常涉及到手动编写大量的实体类、映射XML文件、Mapper接口、Service接口及其实现类以及Controller。然而,这个过程既耗时又容易出错。为了解决这个问题,我们可以利用代码生成工具来自动生成这些文件...

    mybatis配置xml最新dtd文件

    DTD定义了XML文档的结构和规则,确保XML文件的正确性,使得解析器能够理解并处理这些文件。 标题中的"mybatis配置xml最新dtd文件"指的是MyBatis框架中使用的最新的XML配置文件所依赖的DTD文件。这些文件定义了...

    mybatis入门实例(xml)

    首先,MyBatis 的核心是 SQL 映射文件,它位于项目的 resources 目录下,通常命名为 `mybatis-config.xml`。这个配置文件包含了 MyBatis 框架的全局设置,如数据源、事务管理器等。在 XML 文件中,我们可以定义数据...

    IDEA热部署修改mybatis映射文件工具 jr-ide-intellij-nightly.zip

    通常情况下,当我们修改了MyBatis的Mapper XML文件后,需要重启应用才能看到改动的效果,这无疑降低了开发效率。而此工具的出现,允许开发者在不重启应用的情况下,实时更新和查看MyBatis映射文件的变更,极大地提高...

    mybatis生成映射文件和xml文件所需jar包

    在你提到的场景中,我们重点关注的是"mybatis生成映射文件和xml文件"的过程,这通常涉及到逆向工程(Reverse Engineering)或代码生成工具。 首先,MyBatis提供了`mybatis-generator`模块,这是一个代码生成器,...

Global site tag (gtag.js) - Google Analytics