codecamp

HasorDB 映射文件

使用 Mapper 文件的好处是便于维护和管理 SQL,这在团队协作时 review sql 代码比起在程序中用代码来拼接要好。

文档结构​

下面是 HasorDB Mapper 文件基本结构:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//hasor.net//DTD Mapper 1.0//EN"
"https://www.hasor.net/schema/hasordb-mapper.dtd">
<mapper namespace="...">
...
</mapper>
提示
namespace ​通常是配置一个接口类名,这个接口下的每个方法会对应到 mapper 文件中一个具体的 sql 操作上。

在 ​mapper ​根元素下可以使用的顶层 XML 元素有如下几个:

  • resultMap 用于描述如何从查询结果集中加载数据。
  • sql 用于定义一小段可以复用的 SQL 片段。
  • insert 映射 INSERT 语句。
  • update 映射 UPDATE 语句。
  • delete 映射 DELETE 语句。
  • select 映射 SELECT 语句。

select 操作​

select 标签是 HasorDB 中最常用的元素之一。对于简单的情况 select 元素非常简单。例如:

<select id="queryListByAge">
select * from `test_user` where age = #{age}
</select>

select 标签有很多属性下面列出的是每个属性和含义。

属性名 描述
id 必选,用于标识查询命令
statementType 可选,STATEMENTPREPAREDCALLABLE 对应了 StatementPreparedStatement 或 CallableStatement 中的一种。默认值为 PREPARED
timeout 可选,当配置的值大于 0 时会被设置到 Statement.setQueryTimeout,用于表示查询最长等待的超时时间。默认值是 -1
resultMap 可选,对于映射配置的引用。select 标签可以使用 resultMap 和 resultType 其中的一种,不应该同时使用它们。如果没有配置将会按照 map 来处理
resultType 可选,将返回的预期类型的完全限定类名或别名。注意,在集合的情况下,这应该是集合包含的类型,而不是集合本身的类型,不应该同时使用resultMap 和 resultType
fetchSize 可选,当配置的值大于 0 时会被设置到 Statement.setQueryTimeout,用于表示查询最长等待的超时时间。默认值是 -1
resultSetType 可选,FORWARD_ONLYSCROLL_INSENSITIVESCROLL_SENSITIVE 和 DEFAULT 其中的一种。默认值是 DEFAULT 相当于未设置。
multipleResult 可选,FIRSTLASTALL 用于处理多结果集的情况。它们对应的行为是 保留第一个结果集保留最后一个结果集全部保留。默认配置是 LAST

insert, update 和 delete 操作​

insert​、​update​、​delete ​标签本质上是同一个标签,只是通过专门的名字来区分会让人更为容易理解。

一个简单的例子如下:

<insert id="insertUser">
insert into `test_user` (
`id`, `name`, `age`, `create_time`
) values (
#{id}, #{name}, #{age}, #{createTime}
)
</insert>

<update id="updateAge">
update `test_user` set age = #{age} where id = #{id}
</update>

<delete id="deleteById">
delete from `test_user` where id = #{id}
</delete>

insert​、​update​、​delete ​标签都有如下共同的属性。

属性名 描述
id 必选,用于标识查询命令
statementType 可选,STATEMENTPREPAREDCALLABLE 对应了 StatementPreparedStatement 或 CallableStatement 中的一种。默认值为 PREPARED
timeout 可选,当配置的值大于 0 时会被设置到 Statement.setQueryTimeout,用于表示查询最长等待的超时时间。默认值是 -1

selectKey​

对于不支持自增列的数据库,HasorDB 可以使用 ​selectKey ​标签来通过 SQL 方式生成它,比较常见用处是使用数据库的 ​sequence​。 例如:下面 Mapper 配置,在执行 ​insert ​之前会先使用数据库函数生成一个随机数作为主键。

<insert id="insertUser">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
SELECT CONCAT('1', CEILING(RAND() * 1000 + 1000))
</selectKey>
insert into `test_user` (
`id`, `name`, `age`, `create_time`
) values (
#{id}, #{name}, #{age}, #{createTime}
)
</insert>

selectKey ​标签有如下属性。

属性名 描述
keyProperty 必选,用于将 selectKey 执行后的返回值写入到目标的属性名,如果要回写多个属性则,可以使用逗号分割属性名列表。
keyColumn 可选,返回结果集中与属性匹配的列名,如果需要选择多个列,可以使用逗号分割属性名列表。列名和属性名的顺序一致。
order 可选,可以设置为 BEFORE 或 AFTER。如果设置为 BEFORE 它会在执行 insert 之前先执行 selectKey;如果设置为 AFTER 则会在运行完 insert 之后在执行 selectKey。后运行一般用于获取自增主键的返回值。
handler 可选,用于自定义 selectKey 执行逻辑。配置一个全类名,该类要求实现了 net.hasor.db.dal.execute.KeySequenceHolderFactory 接口,并且有一个无参的构造方法。
statementType 可选,STATEMENTPREPAREDCALLABLE 对应了 StatementPreparedStatement 或 CallableStatement 中的一种。默认值为 PREPARED
timeout 可选,当配置的值大于 0 时会被设置到 Statement.setQueryTimeout,用于表示查询最长等待的超时时间。默认值是 -1
resultType 可选,将返回的预期类型的完全限定类名或别名。注意,在集合的情况下,这应该是集合包含的类型,而不是集合本身的类型,不应该同时使用resultMap 和 resultType
fetchSize 可选,当配置的值大于 0 时会被设置到 Statement.setQueryTimeout,用于表示查询最长等待的超时时间。默认值是 -1
resultSetType 可选,FORWARD_ONLYSCROLL_INSENSITIVESCROLL_SENSITIVE 和 DEFAULT 其中的一种。默认值是 DEFAULT 相当于未设置。

sql 代码片段​

此标签可用于定义一段在其它语句中被包含的重用代码片段。例如定义列名。

<sql id="testuser_columns">
name,age,create_time
</sql>

<insert id="insertUser">
insert into `test_user` (
<include refid="testuser_columns"/>
) values (
#{name}, #{age}, now()
)
</insert>

结果集映射​

并不是每一个 ​select ​都必须要求配置 ​resultMap ​默认情况下会使用 Map 来承装返回的数据。

<select id="queryListByAge">
select * from `test_user` where age = #{age}
</select>

但通常 Map 并不是一个很好的模型设计,应该使用一些有意义的 pojo 充当数据对象。HasorDB 支持将一个普通的 pojo 映射到一个结果集上。例如下面这个 Bean:

class net.hasor.db.example.mapper.TestUser

public class TestUser {
private Integer id;
private String name;
private Integer age;
private Date createTime;

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}

可以使用 ​resultType ​属性将查询结果映射到这个 Bean 上。

<select id="queryById" resultType="net.hasor.db.example.mapper.TestUser">
select
id, name, age, create_time
from
test_user
where
id = #{id}
</select>

使用这种方式,HasorDB 会在加载配置文件的时候自动创建一个 ​resultMap​,根据名称将列自动映射到 pojo 的属性上。如果列名不完全匹配,可以在列名上使用 ​as ​子句来匹配映射。例如:

<select id="queryById" resultType="net.hasor.db.example.mapper.TestUser">
select
id, name, age, create_time as createTime
from
test_user
where
id = #{id}
</select>

直接使用 ​resultMap ​的好处是可以更加精细化的控制每一个属性映射,以刚才的映射为例。在不通过 ​as ​改变列名的情况下映射这个 pojo:

<resultMap id="testuser_resultMap" type="net.hasor.db.example.mapper.TestUser">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
<result column="create_time" property="createTime"/>
</resultMap>

<select id="queryById" resultMap="testuser_resultMap">
select
id, name, age, create_time
from
test_user
where
id = #{id}
</select>

resultMap ​标签有如下属性。

属性名 描述
type 必选,类型全名,用于决定映射到的具体类型。
id 可选,如果为空那么将会以 type 属性为替代。主要是用于标识 resultMap。
schema 可选,一个补充选项,通常在使用通用 Mapper 时候用到。它可以决定 映射到的数据库 schema 名字。
table 可选,一个补充选项,通常在使用通用 Mapper 时候用到。它可以决定 映射到的数据库 table 名字。
caseInsensitive 可选,在处理映射列名和属性名时是否对大小写不敏感,默认是 true 不敏感。对于某些数据库查询结果始终返回大写,利用这个功能可以方便的映射到属性上。
mapUnderscoreToCamelCase 可选,用于决定属性名在映射到列名时,是否按照驼峰命名法转换为下划线命名法,例如:属性名 createTime 被转换为 create_time。默认是 false 不转换
autoMapping 可选,用于决定是否进行 自动映射。默认是 true 自动映射。

id &

id ​和 ​result ​都是用于映射列和属性之间的映射关系。不同的是 id 可以方便的指出列在数据中是否为主键。

在使用通用 Mapper 时,CURD 操作将会依赖 ​id​、​table​、​schema ​这些属性用以生成 SQL。

它们每个标签都有下面这些属性

属性名 描述
property 必选,pojo 的属性名。
column 必选,查询结果的列名。
javaType 可选,通常 HasorDB 会识别到具体类型,但如果 pojo 的属性是一个抽象类或者接口,则可以配置 javaType 来指定具体的实现类。
jdbcType 可选,对应的 JDBC 类型。HasorDB 将会遵循 Java 和 JDBC 类型关系 进行映射
typeHandler 可选,通常 HasorDB 会根据 类型映射 自动寻找列的读写器。该属性允许自定义属性读写器。

多结果映射​

例如,一个 ​select ​配置了两个 查询语句。或者调用的存储过程中执行了两条 查询 SQL。​resultType ​中以逗号作为分割将两个结果分别映射到两个类型上。

提示
使用 ​resultMap ​同样也可以通过逗号作为分割,映射多个结果。
<select id="multipleListByAge" multipleResult="ALL"
resultType="net.hasor.db.example.mapper.TestUserPojo,net.hasor.db.example.mapper.TestUser">
select id, name, age, create_time as createTime from `test_user` where age = #{age};
select * from `test_user`;
</select>

自动映射​

上面已经介绍过 ​resultMap ​和 ​resultType ​的能力,在本节可以了解通过自动映射机制来混合两种操作。

HasorDB 会尝试将结果集中的列名作为属性名进行写入,匹配的时会忽略大小写。 这意味着,如果找到名为 ​ID ​的列和名为 ​ID ​的属性,HasorDB 将使用 ​ID ​列值设置 ​ID ​属性。

<resultMap id="testuser_resultMap" type="net.hasor.db.example.mapper.TestUser">
<result property="createTime" column="create_time"/>
</resultMap>

<select id="queryById" resultMap="testuser_resultMap">
select
id, name, age, create_time
from
test_user
where
id = #{id}
</select>

通常数据库列的命名使用大写字母和下划线,这与 java 通常遵循驼峰命名约定有一定的差异。 若想使它们之间自定映射需要设置 ​mapUnderscoreToCamelCase ​为 ​true

<resultMap id="testuser_resultMap" type="net.hasor.db.example.mapper.TestUser" 
mapUnderscoreToCamelCase="true"/>

<select id="queryById" resultMap="testuser_resultMap">
select
id, name, age, create_time
from
test_user
where
id = #{id}
</select>
提示
默认情况下 HasorDB 是启用自动映射的,如果你不像使用这一特性。则可以通过设置 ​autoMapping ​为 ​false ​来关闭它。


HasorDB 仅生成SQL
HasorDB Mapper 配置动态SQL
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }