HasorDB 映射文件

2022-01-10 10:23 更新

使用 Mapper 文件的好處是便于維護和管理 SQL,這在團隊協(xié)作時 review sql 代碼比起在程序中用代碼來拼接要好。

文檔結(jié)構(gòu)?

下面是 HasorDB Mapper 文件基本結(jié)構(gòu):

<?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 用于描述如何從查詢結(jié)果集中加載數(shù)據(jù)。
  • 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 可選,STATEMENTPREPARED、CALLABLE 對應了 StatementPreparedStatement 或 CallableStatement 中的一種。默認值為 PREPARED
timeout 可選,當配置的值大于 0 時會被設(shè)置到 Statement.setQueryTimeout,用于表示查詢最長等待的超時時間。默認值是 -1
resultMap 可選,對于映射配置的引用。select 標簽可以使用 resultMap 和 resultType 其中的一種,不應該同時使用它們。如果沒有配置將會按照 map 來處理
resultType 可選,將返回的預期類型的完全限定類名或別名。注意,在集合的情況下,這應該是集合包含的類型,而不是集合本身的類型,不應該同時使用resultMap 和 resultType。
fetchSize 可選,當配置的值大于 0 時會被設(shè)置到 Statement.setQueryTimeout,用于表示查詢最長等待的超時時間。默認值是 -1
resultSetType 可選,FORWARD_ONLY、SCROLL_INSENSITIVESCROLL_SENSITIVE 和 DEFAULT 其中的一種。默認值是 DEFAULT 相當于未設(shè)置。
multipleResult 可選,FIRST、LAST、ALL 用于處理多結(jié)果集的情況。它們對應的行為是 保留第一個結(jié)果集保留最后一個結(jié)果集、全部保留。默認配置是 LAST

insert, update 和 delete 操作?

?insert?、?update?、?delete ?標簽本質(zhì)上是同一個標簽,只是通過專門的名字來區(qū)分會讓人更為容易理解。

一個簡單的例子如下:

<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 可選,STATEMENT、PREPAREDCALLABLE 對應了 StatementPreparedStatement 或 CallableStatement 中的一種。默認值為 PREPARED
timeout 可選,當配置的值大于 0 時會被設(shè)置到 Statement.setQueryTimeout,用于表示查詢最長等待的超時時間。默認值是 -1

selectKey?

對于不支持自增列的數(shù)據(jù)庫,HasorDB 可以使用 ?selectKey ?標簽來通過 SQL 方式生成它,比較常見用處是使用數(shù)據(jù)庫的 ?sequence?。 例如:下面 Mapper 配置,在執(zhí)行 ?insert ?之前會先使用數(shù)據(jù)庫函數(shù)生成一個隨機數(shù)作為主鍵。

<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 執(zhí)行后的返回值寫入到目標的屬性名,如果要回寫多個屬性則,可以使用逗號分割屬性名列表。
keyColumn 可選,返回結(jié)果集中與屬性匹配的列名,如果需要選擇多個列,可以使用逗號分割屬性名列表。列名和屬性名的順序一致。
order 可選,可以設(shè)置為 BEFORE 或 AFTER。如果設(shè)置為 BEFORE 它會在執(zhí)行 insert 之前先執(zhí)行 selectKey;如果設(shè)置為 AFTER 則會在運行完 insert 之后在執(zhí)行 selectKey。后運行一般用于獲取自增主鍵的返回值。
handler 可選,用于自定義 selectKey 執(zhí)行邏輯。配置一個全類名,該類要求實現(xiàn)了 net.hasor.db.dal.execute.KeySequenceHolderFactory 接口,并且有一個無參的構(gòu)造方法。
statementType 可選,STATEMENT、PREPARED、CALLABLE 對應了 StatementPreparedStatement 或 CallableStatement 中的一種。默認值為 PREPARED
timeout 可選,當配置的值大于 0 時會被設(shè)置到 Statement.setQueryTimeout,用于表示查詢最長等待的超時時間。默認值是 -1
resultType 可選,將返回的預期類型的完全限定類名或別名。注意,在集合的情況下,這應該是集合包含的類型,而不是集合本身的類型,不應該同時使用resultMap 和 resultType。
fetchSize 可選,當配置的值大于 0 時會被設(shè)置到 Statement.setQueryTimeout,用于表示查詢最長等待的超時時間。默認值是 -1
resultSetType 可選,FORWARD_ONLYSCROLL_INSENSITIVE、SCROLL_SENSITIVE 和 DEFAULT 其中的一種。默認值是 DEFAULT 相當于未設(shè)置。

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>

結(jié)果集映射?

并不是每一個 ?select ?都必須要求配置 ?resultMap ?默認情況下會使用 Map 來承裝返回的數(shù)據(jù)。

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

但通常 Map 并不是一個很好的模型設(shè)計,應該使用一些有意義的 pojo 充當數(shù)據(jù)對象。HasorDB 支持將一個普通的 pojo 映射到一個結(jié)果集上。例如下面這個 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 ?屬性將查詢結(jié)果映射到這個 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 會在加載配置文件的時候自動創(chuàng)建一個 ?resultMap?,根據(jù)名稱將列自動映射到 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 時候用到。它可以決定 映射到的數(shù)據(jù)庫 schema 名字。
table 可選,一個補充選項,通常在使用通用 Mapper 時候用到。它可以決定 映射到的數(shù)據(jù)庫 table 名字。
caseInsensitive 可選,在處理映射列名和屬性名時是否對大小寫不敏感,默認是 true 不敏感。對于某些數(shù)據(jù)庫查詢結(jié)果始終返回大寫,利用這個功能可以方便的映射到屬性上。
mapUnderscoreToCamelCase 可選,用于決定屬性名在映射到列名時,是否按照駝峰命名法轉(zhuǎn)換為下劃線命名法,例如:屬性名 createTime 被轉(zhuǎn)換為 create_time。默認是 false 不轉(zhuǎn)換
autoMapping 可選,用于決定是否進行 自動映射。默認是 true 自動映射。

id &

?id ?和 ?result ?都是用于映射列和屬性之間的映射關(guān)系。不同的是 id 可以方便的指出列在數(shù)據(jù)中是否為主鍵。

在使用通用 Mapper 時,CURD 操作將會依賴 ?id?、?table?、?schema ?這些屬性用以生成 SQL。

它們每個標簽都有下面這些屬性

屬性名 描述
property 必選,pojo 的屬性名。
column 必選,查詢結(jié)果的列名。
javaType 可選,通常 HasorDB 會識別到具體類型,但如果 pojo 的屬性是一個抽象類或者接口,則可以配置 javaType 來指定具體的實現(xiàn)類。
jdbcType 可選,對應的 JDBC 類型。HasorDB 將會遵循 Java 和 JDBC 類型關(guān)系 進行映射
typeHandler 可選,通常 HasorDB 會根據(jù) 類型映射 自動尋找列的讀寫器。該屬性允許自定義屬性讀寫器。

多結(jié)果映射?

例如,一個 ?select ?配置了兩個 查詢語句?;蛘哒{(diào)用的存儲過程中執(zhí)行了兩條 查詢 SQL。?resultType ?中以逗號作為分割將兩個結(jié)果分別映射到兩個類型上。

提示
使用 ?resultMap ?同樣也可以通過逗號作為分割,映射多個結(jié)果。
<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>

自動映射?

上面已經(jīng)介紹過 ?resultMap ?和 ?resultType ?的能力,在本節(jié)可以了解通過自動映射機制來混合兩種操作。

HasorDB 會嘗試將結(jié)果集中的列名作為屬性名進行寫入,匹配的時會忽略大小寫。 這意味著,如果找到名為 ?ID ?的列和名為 ?ID ?的屬性,HasorDB 將使用 ?ID ?列值設(shè)置 ?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>

通常數(shù)據(jù)庫列的命名使用大寫字母和下劃線,這與 java 通常遵循駝峰命名約定有一定的差異。 若想使它們之間自定映射需要設(shè)置 ?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 是啟用自動映射的,如果你不像使用這一特性。則可以通過設(shè)置 ?autoMapping ?為 ?false ?來關(guān)閉它。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號