• SQL 映射 XML 文件


    MyBatis 真正强大之处就在这些映射语句,也就是它的魔力所在。对于它的强大功能,SQL 映射文件的配置却非常简单。如果您比较 SQL 映射文件配置与 JDBC 代码,您很快可以发现,使用 SQL 映射文件配置可以节省95%的代码量。MyBatis 被创建来专注于 SQL,但又给您自己的实现极大的空间。

    SQL 映射 XML 文件只有一些基本的元素需要配置,并且要按照下面的顺序来定义:

    • cache:在特定的命名空间配置缓存。
    • cache-ref:引用另外一个命名空间配置的缓存.
    • resultMap:最复杂也是最强大的元素,用来描述如何从数据库结果集里加载对象。
    • parameterMap:不推荐使用!在旧的版本里使用的映射配置,这个元素在将来可能会被删除,因此不再进行描述。
    • sql:能够被其它语句重用的SQL块。
    • insert:INSERT 映射语句
    • update:UPDATE 映射语句
    • delete:DELEETE 映射语句
    • select:SELECT 映射语句

    一、Select元素

    Select 是 MyBatis 中最常用的元素之一。除非您把数据取回来,否则把数据放在数据库是没什么意义的,因此大部分的应用查询数据远多于修改数据。对每一次插入、修改、删除数据都可能伴有大量的查询。这是 MyBatis 基本设计原则之一,也就是为什么把这么多的焦点和努力放在查询和结果集映射上。对简单的查询,select 元素的配置是相当简单的,如:

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

    这条语句叫做 selectPerson,以 int 型(或者 Integer 型)作为参数,并返回一个以数据库列名作为键值的 HashMap。

    注意这个参数的表示方法:#{id}

    它告诉 MyBatis 生成 PreparedStatement 参数。对于 JDBC,像这个参数会被标识为"?",然后传递给 PreparedStatement,像这样:

    //Similar JDBC code, NOT 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>

    正如您看到,insert 元素有更多一些的扩展属性及子元素,允许您使用多种方式自动生成主键。

    首先,如果您使用的数据库支持自动生成主键(如:MySQL 和 SQL Server),那么您就可以简单地将 useGeneratedKeys 设置为"true",然后使用 keyProperty 设置您希望自动生成主键的字段就可以了。例如,如果上面提到的 Author 表使用一个字段自动生成主键,那么配置语句就可以修改为:

    <insert id="insertAuthor" parameterType="domain.blog.Author" useGeneratedKeys="true" keyProperty="id">
        insert into Author(username,password,email,bio)
        values(#{username},#{password},#{email},#{bio})
    </insert>

    MyBatis 还有另外一种方式为不支持自动生成主键的数据库及 JDBC 驱动来生成键值。下面展示一个能够随机生成 ID 的例子(也许您不会这么做,这仅仅是演示 MyBatis 的功能):

    <inser id="insertAuthor" parameterType="domain.blog.Author">
        <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>

    在上面的例子中,selectKey 语句首先会执行,Author 表的 ID 首先会被设值,然后才会调用 insert 语句。这相当于在您的数据库中自动生成键值,不需要编写复杂的 Java代码。

    selectKey 元素描述如下:

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

    三、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)

    在前面的语句中,我们可以看到一些例子中简单的参数(用于代入 SQL 语句中的可替换变量,如 #{id} )。参数是 MyBatis 中非常强大的配置属性,基本上,90%的情况都会用到,如:

    <select id="selectUsers" parameterType="int" resultType="User">
        select id,username,password
        from users
        where id=#{id}
    </select>

    上面的例子演示了一个非常简单的命名参数映射,parameterType 被设置为 "int"。参数可以设置为任何类型。像基本数据类型或者像 Integer 和 String 这样的简单的数据对象,(因为没有相关属性)将使用全部参数值。而如果传递的是复杂对象(一般是指 JavaBean),那情况就有所不同。例如::

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

    如果参数对象 User 被传递给 SQL 语句,那么将会搜寻 PreparedStatement 里的 id,username 和 password 属性,并被 User 对象里相应的属性值替换。

    这种传递参数到语句的方式非常优雅和简单。但参数映射还在很多特性。

    首先,像 MyBatis 其它部分一样,参数可以指定许多的数据类型。

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

    像 MyBatis 的其它部分一样,这个 javaType 是由参数对象决定,除了 HashMap 以外。然后这个 javaType 应该确保指定正确的 TypeHandler 被使用。

    注意:如果传递了一个空值,那这个 JDBCType 对于所有 JDBC 允许为空的列来说是必须的。您可以研读一下关于 PreparedStatement.setNull() 的 JavaDocs 文档。

    对于需要自定义类型处理,您也可以指定一个特殊的 TypeHandler 类或者别名,如:

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

    当然,这看起来更加复杂了,不过,这种情况比较少见。

    对于数据类型,可以使用 numericScale 来指定小数位的长度。

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

    最后,mode 属性允许您指定 IN、OUT 或 INOUT参数。如果参数是 OUT 或 INOUT,参数对象属的实际值将会改变,正如您希望调用一个输出参数。如果 mode=OUT (或者 INOUT ),并且 jdbcType=CURSOR (如 Oracle 的 REFCURSOR),您必须指定一个 resultMap 映射结果集给这个参数类型。注意这里的 javaType 类型是可选的,如果为空值而 jdbcType=CURSOR 的话,则会自动地设给 ResultSet。

    #{department,
        mode=OUT,
        jdbcType=CURSOR,
        javaType=ResultSet,
        resultMap=departmentResultMap}

    MyBatis 也支持像 structs 这样高级的数据类型,但当您把 mode 设置为 out 的时候,您必须把类型名告诉执行语句。例如:

    #{middleInitial,
        mode=OUT,
        jdbcType=STRUCT,
        jdbcTypeName=MY_TYPE,
        resultMap=departmentResultMap}

    尽管有这些强大的选项,但是大多数情况下您只需指定属性名,MyBatis 将会识别其它部分的设置。最多就是给可以为 null 值的列指定 jdbcType:

    #{firstName}
    #{middleInitial,jdbcType=VARCHAR}
    #{lastName}

    字符串替换

    默认的情况下,使用 #{} 语法会促使 MyBatis 生成 PreparedStatement 并且安全地设置 PreparedStatement参数(=?)值。尽量这是安全、快捷并且是经常使用的,但有时候您可能想

    直接未更改的字符串代入到 SQL 语句中。比如说,对于ORDERBY,您可以这样使用

    ORDERBY ${columnName}

    这样 MyBatis 就不会修改这个字符串了。

    警告:这种不加修改地接收用户输入并应用到语句的方式,是非常不安全的。这使用户能够进行 SQL 注入,破坏代码。所以,要么这些字段不允许用户输入,要么用户每次输入后都进行检测和规避。

    五、resultMap元素

    resultMap 元素是 MyBatis 中最重要最强大的元素。与使用 JDBC 从结果集获取数据相比,它可以省掉 90% 的代码,也可以允许您做一些 JDBC 不支持的事。事实上,要写一个类似于连结映射(join mapping)这样复杂的交互代码,可能需要上千行的代码。设计 ResultMaps 的目的,就是只使用简单的配置语句而不需要详细地处理结果集映射,对更复杂的语句除了使用一些必须的语句描述以外,就不需要其它的处理了。

    您可能已经看到过这样简单映射语句,它并没有使用 resultMap,例如:

    <select id="selectUsers" parameterType="int" resultType="hashmap">
        select id,username,hashedPassword
        from some_table
        where id=#{id}
    </select>

    像上面的语句,所有结果集将会自动地映射到以列表为 key 的 HasMap(由resultType指定)中。虽然这对许多场合下有用,但是 HashMap 却不是非常好的域模型。更多的情况是使用 JavaBeans 或者 POJOs 作为域模型。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;
        }
    }

    基于 JavaBeans 规范,上面的类有3个属性:id、username 和 hashedPassword。这3个属性对应 select 语句的列名。这样的 JavaBean 可以像 HashMap 一样简单地映射到 ResultSet 结果集。

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

    别忘了别名是您的朋友,使用别名您不用输入那长长的类路径。例如:

    <!--In Config XML file-->
    <typeAlias type="com.someapp.model.User" alias="User"/>
    
    <!--In SQL Mapping XML file-->
    <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>

    ResultMaps 的知识您可能已经学到了许多,但还有一个您从没见到过。为了举例,让我们看看最后一个例子,作为另一种解决列名不匹配的方法。

    <resultMap id="userResultMap" type="User">
        <id property="id" column="user_id"/>
        <result property="username" column="username"/>
        <result property="password" column="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>

    一切就是这么简单!

  • 相关阅读:
    call与apply
    git的.gitignore文件内容
    docker安装nacos
    项目某些代码突然报红的问题
    用打字查看当前时间以及显示数字各种形式
    mybatisPlus crud操作注意事项
    nginx location关于root、alias配置的区别
    docker安装kafka
    docker基础容器中bash: vi: command not found问题解决
    docker安装fastdfs
  • 原文地址:https://www.cnblogs.com/jwen1994/p/10896916.html
Copyright © 2020-2023  润新知