MyBatis-2. Mapper XML文件

SQL 映射文件的頂級(jí)元素(按照它們應(yīng)該被定義的順序):

  • cache – 給定命名空間的緩存配置。
  • cache-ref – 其他命名空間緩存配置的引用。
  • resultMap – 是最復(fù)雜也是最強(qiáng)大的元素,用來(lái)描述如何從數(shù)據(jù)庫(kù)結(jié)果集中來(lái)加載對(duì)象。
  • parameterMap – 已廢棄!老式風(fēng)格的參數(shù)映射。內(nèi)聯(lián)參數(shù)是首選,這個(gè)元素可能在將來(lái)被移除,這里不會(huì)記錄。
  • sql – 可被其他語(yǔ)句引用的可重用語(yǔ)句塊。
  • insert – 映射插入語(yǔ)句
  • update – 映射更新語(yǔ)句
  • delete – 映射刪除語(yǔ)句
  • select – 映射查詢(xún)語(yǔ)句

select

查詢(xún)語(yǔ)句的元素
例子:

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

這個(gè)語(yǔ)句被稱(chēng)作 selectPerson,接受一個(gè) int(或 Integer)類(lèi)型的參數(shù),并返回一個(gè) HashMap 類(lèi)型的對(duì)象,其中的鍵是列名,值便是結(jié)果行中的對(duì)應(yīng)值。
注意:

#{id}

這是一個(gè)預(yù)處理語(yǔ)句參數(shù),通過(guò)JDBC會(huì)被處理成:

// Similar JDBC code, NOT MyBatis…
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);

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">

select元素的屬性描述:

屬性 描述
id 在命名空間的唯一標(biāo)識(shí)符,可以用來(lái)引用這個(gè)語(yǔ)句。
parameterType 將會(huì)傳入這條語(yǔ)句的參數(shù)類(lèi)的完全限定名或別名。這個(gè)屬性是可選的,因?yàn)?MyBatis 可以通過(guò) TypeHandler 推斷出具體傳入語(yǔ)句的參數(shù),默認(rèn)值為 unset。
parameterMap 這是引用外部 parameterMap 的已經(jīng)被廢棄的方法。使用內(nèi)聯(lián)參數(shù)映射和 parameterType 屬性。
resultType 從這條語(yǔ)句中返回的期望類(lèi)型的類(lèi)的完全限定名或別名。注意如果是集合情形,那應(yīng)該是集合可以包含的類(lèi)型,而不能是集合本身。使用 resultType 或 resultMap,但不能同時(shí)使用。
resultMap 外部 resultMap 的命名引用。結(jié)果集的映射是 MyBatis 最強(qiáng)大的特性,對(duì)其有一個(gè)很好的理解的話,許多復(fù)雜映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同時(shí)使用。
flushCache 將其設(shè)置為 true,任何時(shí)候只要語(yǔ)句被調(diào)用,都會(huì)導(dǎo)致本地緩存和二級(jí)緩存都會(huì)被清空,默認(rèn)值:false。
useCache 將其設(shè)置為 true,將會(huì)導(dǎo)致本條語(yǔ)句的結(jié)果被二級(jí)緩存,默認(rèn)值:對(duì) select 元素為 true。
timeout 這個(gè)設(shè)置是在拋出異常之前,驅(qū)動(dòng)程序等待數(shù)據(jù)庫(kù)返回請(qǐng)求結(jié)果的秒數(shù)。默認(rèn)值為 unset(依賴(lài)驅(qū)動(dòng))。
fetchSize 這是嘗試影響驅(qū)動(dòng)程序每次批量返回的結(jié)果行數(shù)和這個(gè)設(shè)置值相等。默認(rèn)值為 unset(依賴(lài)驅(qū)動(dòng))。
statementType STATEMENT,PREPARED 或 CALLABLE 的一個(gè)。這會(huì)讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認(rèn)值:PREPARED。
resultSetType FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一個(gè),默認(rèn)值為 unset (依賴(lài)驅(qū)動(dòng))。
databaseId 如果配置了 databaseIdProvider,MyBatis 會(huì)加載所有的不帶 databaseId 或匹配當(dāng)前 databaseId 的語(yǔ)句;如果帶或者不帶的語(yǔ)句都有,則不帶的會(huì)被忽略。
resultOrdered 這個(gè)設(shè)置僅針對(duì)嵌套結(jié)果 select 語(yǔ)句適用:如果為 true,就是假設(shè)包含了嵌套結(jié)果集或是分組了,這樣的話當(dāng)返回一個(gè)主結(jié)果行的時(shí)候,就不會(huì)發(fā)生有對(duì)前面結(jié)果集的引用的情況。這就使得在獲取嵌套的結(jié)果集的時(shí)候不至于導(dǎo)致內(nèi)存不夠用。默認(rèn)值:false。
resultSets 這個(gè)設(shè)置僅對(duì)多結(jié)果集的情況適用,它將列出語(yǔ)句執(zhí)行后返回的結(jié)果集并每個(gè)結(jié)果集給一個(gè)名稱(chēng),名稱(chēng)是逗號(hào)分隔的。

insert, update 和 delete

數(shù)據(jù)變更語(yǔ)句。
例子:

<insert
  id="insertAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  keyProperty=""
  keyColumn=""
  useGeneratedKeys=""
  timeout="20">

<update
  id="updateAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">

<delete
  id="deleteAuthor"
  parameterType="domain.blog.Author"
  flushCache="true"
  statementType="PREPARED"
  timeout="20">
屬性和描述
屬性 描述
id 命名空間中的唯一標(biāo)識(shí)符,可被用來(lái)代表這條語(yǔ)句。
parameterType 將要傳入語(yǔ)句的參數(shù)的完全限定類(lèi)名或別名。這個(gè)屬性是可選的,因?yàn)?MyBatis 可以通過(guò) TypeHandler 推斷出具體傳入語(yǔ)句的參數(shù),默認(rèn)值為 unset。
parameterMap 這是引用外部 parameterMap 的已經(jīng)被廢棄的方法。使用內(nèi)聯(lián)參數(shù)映射和 parameterType 屬性。
flushCache 將其設(shè)置為 true,任何時(shí)候只要語(yǔ)句被調(diào)用,都會(huì)導(dǎo)致本地緩存和二級(jí)緩存都會(huì)被清空,默認(rèn)值:true(對(duì)應(yīng)插入、更新和刪除語(yǔ)句)。
timeout 這個(gè)設(shè)置是在拋出異常之前,驅(qū)動(dòng)程序等待數(shù)據(jù)庫(kù)返回請(qǐng)求結(jié)果的秒數(shù)。默認(rèn)值為 unset(依賴(lài)驅(qū)動(dòng))。
statementType STATEMENT,PREPARED 或 CALLABLE 的一個(gè)。這會(huì)讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認(rèn)值:PREPARED。
useGeneratedKeys (僅對(duì) insert 和 update 有用)這會(huì)令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來(lái)取出由數(shù)據(jù)庫(kù)內(nèi)部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)的自動(dòng)遞增字段),默認(rèn)值:false。
keyProperty (僅對(duì) insert 和 update 有用)唯一標(biāo)記一個(gè)屬性,MyBatis 會(huì)通過(guò) getGeneratedKeys 的返回值或者通過(guò) insert 語(yǔ)句的 selectKey 子元素設(shè)置它的鍵值,默認(rèn):unset。如果希望得到多個(gè)生成的列,也可以是逗號(hào)分隔的屬性名稱(chēng)列表。
keyColumn (僅對(duì) insert 和 update 有用)通過(guò)生成的鍵值設(shè)置表中的列名,這個(gè)設(shè)置僅在某些數(shù)據(jù)庫(kù)(像 PostgreSQL)是必須的,當(dāng)主鍵列不是表中的第一列的時(shí)候需要設(shè)置。如果希望得到多個(gè)生成的列,也可以是逗號(hào)分隔的屬性名稱(chēng)列表。
databaseId 如果配置了 databaseIdProvider,MyBatis 會(huì)加載所有的不帶 databaseId 或匹配當(dāng)前 databaseId 的語(yǔ)句;如果帶或者不帶的語(yǔ)句都有,則不帶的會(huì)被忽略。

insert, update, delete 語(yǔ)句的示例:

<insert id="insertAuthor">
  insert into Author (id,username,password,email,bio)
  values (#{id},#{username},#{password},#{email},#{bio})
</insert>

<update id="updateAuthor">
  update Author set
    username = #{username},
    password = #{password},
    email = #{email},
    bio = #{bio}
  where id = #{id}
</update>

<delete id="deleteAuthor">
  delete from Author where id = #{id}
</delete>

如果數(shù)據(jù)庫(kù)支持自動(dòng)生成主鍵的字段,可以設(shè)置useGenaratedKeys="true",再將keyProperty設(shè)置到目標(biāo)屬性。例如,下例中,Author表對(duì)id屬性使用了自動(dòng)生成的類(lèi)型:

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

對(duì)于多行插入(需要數(shù)據(jù)庫(kù)支持),傳入一個(gè)Authors數(shù)組或集合,并返回自動(dòng)生成的主鍵:

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

如果數(shù)據(jù)庫(kù)不支持自動(dòng)主鍵(方法不建議。但是沒(méi)有提出更好的解決辦法):

<insert id="insertAuthor">
  <?-- selectKey 元素將會(huì)首先運(yùn)行,Author 的 id 會(huì)被設(shè)置,然后插入語(yǔ)句會(huì)被調(diào)用。這給你了一個(gè)和數(shù)據(jù)庫(kù)中來(lái)處理自動(dòng)生成的主鍵類(lèi)似的行為,避免了使 Java 代碼變得復(fù)雜。-->
  <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 元素描述如下:

<selectKey
  keyProperty="id"
  resultType="int"
  order="BEFORE"
  statementType="PREPARED">
屬性 描述
keyProperty selectKey 語(yǔ)句結(jié)果應(yīng)該被設(shè)置的目標(biāo)屬性。如果希望得到多個(gè)生成的列,也可以是逗號(hào)分隔的屬性名稱(chēng)列表。
keyColumn 匹配屬性的返回結(jié)果集中的列名稱(chēng)。如果希望得到多個(gè)生成的列,也可以是逗號(hào)分隔的屬性名稱(chēng)列表。
resultType 結(jié)果的類(lèi)型。MyBatis 通常可以推算出來(lái),但是為了更加確定寫(xiě)上也不會(huì)有什么問(wèn)題。MyBatis 允許任何簡(jiǎn)單類(lèi)型用作主鍵的類(lèi)型,包括字符串。如果希望作用于多個(gè)生成的列,則可以使用一個(gè)包含期望屬性的 Object 或一個(gè) Map。
order 這可以被設(shè)置為 BEFORE 或 AFTER。如果設(shè)置為 BEFORE,那么它會(huì)首先選擇主鍵,設(shè)置 keyProperty 然后執(zhí)行插入語(yǔ)句。如果設(shè)置為 AFTER,那么先執(zhí)行插入語(yǔ)句,然后是 selectKey 元素 - 這和像 Oracle 的數(shù)據(jù)庫(kù)相似,在插入語(yǔ)句內(nèi)部可能有嵌入索引調(diào)用。
statementType 與前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 語(yǔ)句的映射類(lèi)型,分別代表 PreparedStatement 和 CallableStatement 類(lèi)型。

sql

這個(gè)元素可以被用來(lái)定義可重用的 SQL 代碼段,可以包含在其他語(yǔ)句中。它可以被靜態(tài)地(在加載參數(shù)) 參數(shù)化. 不同的屬性值通過(guò)包含的實(shí)例變化. 比如:

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

這個(gè) SQL 片段可以被包含在其他語(yǔ)句中,例如:

<select id="selectUsers" resultType="map">
  select
    <include refid="userColumns"><property name="alias" value="t1"/></include>,
    <include refid="userColumns"><property name="alias" value="t2"/></include>
  from some_table t1
    cross join some_table t2
</select>

屬性值也可以被用在 include 元素的 refid 屬性里(
<include refid="${include_target}"/>
)或 include 內(nèi)部語(yǔ)句中(
${prefix}Table
),例如:

<sql id="sometable">
  ${prefix}Table
</sql>

<sql id="someinclude">
  from
    <include refid="${include_target}"/>
</sql>
<select id="select" resultType="map">
  select
    field1, field2, field3
  <include refid="someinclude">
    <property name="prefix" value="Some"/>
    <property name="include_target" value="sometable"/>
  </include>
</select>

參數(shù)(Parameters)

參數(shù)也可以指定一個(gè)特殊的數(shù)據(jù)類(lèi)型。

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

javaType 通常可以由參數(shù)對(duì)象確定,除非該對(duì)象是一個(gè) HashMap。這時(shí)所使用的 TypeHandler 應(yīng)該明確指明 javaType。

NOTE 如果一個(gè)列允許 null 值,并且會(huì)傳遞值 null 的參數(shù),就必須要指定 JDBC Type。

定制類(lèi)型處理方式,可以指定一個(gè)特殊的類(lèi)型處理器類(lèi)(或別名),比如:

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

對(duì)于數(shù)值類(lèi)型,可以設(shè)置小數(shù)保留位數(shù),來(lái)確定小數(shù)點(diǎn)后保留的位數(shù)。

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

mode 屬性允許你指定 IN,OUT 或 INOUT 參數(shù)。如果參數(shù)為 OUT 或 INOUT,參數(shù)對(duì)象屬性的真實(shí)值將會(huì)被改變,就像你在獲取輸出參數(shù)時(shí)所期望的那樣。
如果 mode 為 OUT(或 INOUT),而且 jdbcType 為 CURSOR(也就是 Oracle 的 REFCURSOR),你必須指定一個(gè) resultMap 來(lái)映射結(jié)果集 ResultMap 到參數(shù)類(lèi)型。要注意這里的 javaType 屬性是可選的,如果留空并且 jdbcType 是 CURSOR,它會(huì)被自動(dòng)地被設(shè)為 ResultMap。

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

MyBatis 也支持很多高級(jí)的數(shù)據(jù)類(lèi)型,比如結(jié)構(gòu)體,但是當(dāng)注冊(cè) out 參數(shù)時(shí)你必須告訴它語(yǔ)句類(lèi)型名稱(chēng)。比如(再次提示,在實(shí)際中要像這樣不能換行):

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

盡管所有這些選項(xiàng)很強(qiáng)大,但大多時(shí)候你只須簡(jiǎn)單地指定屬性名,其他的事情 MyBatis 會(huì)自己去推斷,頂多要為可能為空的列指定 jdbcType。

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}
字符串替換

默認(rèn)情況下,使用 #{} 格式的語(yǔ)法會(huì)導(dǎo)致 MyBatis 創(chuàng)建 PreparedStatement 參數(shù)并安全地設(shè)置參數(shù)(就像使用 ? 一樣)。這樣做更安全,更迅速,通常也是首選做法,不過(guò)有時(shí)你就是想直接在 SQL 語(yǔ)句中插入一個(gè)不轉(zhuǎn)義的字符串。比如,像 ORDER BY,你可以這樣來(lái)使用:

ORDER BY ${columnName}

這里 MyBatis 不會(huì)修改或轉(zhuǎn)義字符串。

NOTE 用這種方式接受用戶(hù)的輸入,并將其用于語(yǔ)句中的參數(shù)是不安全的,會(huì)導(dǎo)致潛在的 SQL 注入攻擊,因此要么不允許用戶(hù)輸入這些字段,要么自行轉(zhuǎn)義并檢驗(yàn)。

Result Maps

ResultMap 的設(shè)計(jì)思想是,簡(jiǎn)單的語(yǔ)句不需要明確的結(jié)果映射,而復(fù)雜一點(diǎn)的語(yǔ)句只需要描述它們的關(guān)系就行了。

簡(jiǎn)單的映射語(yǔ)句中沒(méi)有明確的resultMap:

<?--這里只是簡(jiǎn)單地將所有的列映射到 HashMap 的鍵上,這由 resultType 屬性指定。-->
<select id="selectUsers" resultType="map">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

如果,一個(gè)基于 JavaBean 的規(guī)范的,有 3 個(gè)屬性:id,username 和 hashedPassword的User類(lèi)。
這樣的一個(gè) JavaBean 可以被映射到 ResultSet,就像映射到 HashMap 一樣簡(jiǎn)單。

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

可以使用類(lèi)別名來(lái)簡(jiǎn)化;

<!-- In mybatis-config.xml file -->
<typeAlias type="com.someapp.model.User" alias="User"/>

<!-- In SQL Mapping XML file -->
<select id="selectUsers" resultType="User">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

這些情況下,MyBatis 會(huì)在幕后自動(dòng)創(chuàng)建一個(gè) ResultMap,再基于屬性名來(lái)映射列到 JavaBean 的屬性上。如果列名和屬性名沒(méi)有精確匹配,可以在 SELECT 語(yǔ)句中對(duì)列使用別名(這是一個(gè) 基本的 SQL 特性)來(lái)匹配標(biāo)簽。比如:。比如:

<select id="selectUsers" resultType="User">
  select
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "hashedPassword"
  from some_table
  where id = #{id}
</select>

還可以使用外部的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>

這樣,引用他的語(yǔ)句使用resultMap屬性就可以了(注意去掉了 resultType 屬性)。比如:
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>

高級(jí)結(jié)果映射

一個(gè)復(fù)雜的映射:

<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
  <idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" 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" javaType="Author"/>
  <collection property="comments" ofType="Comment">
    <id property="id" column="comment_id"/>
  </collection>
  <collection property="tags" ofType="Tag" >
    <id property="id" column="tag_id"/>
  </collection>
  <discriminator javaType="int" column="draft">
    <case value="1" resultType="DraftPost"/>
  </discriminator>
</collection>
</resultMap>

resultMap:

  • constructor - 用于在實(shí)例化類(lèi)時(shí),注入結(jié)果到構(gòu)造方法中
    • idArg - ID 參數(shù);標(biāo)記出作為 ID 的結(jié)果可以幫助提高整體性能
    • arg - 將被注入到構(gòu)造方法的一個(gè)普通結(jié)果
  • id – 一個(gè) ID 結(jié)果;標(biāo)記出作為 ID 的結(jié)果可以幫助提高整體性能
  • result – 注入到字段或 JavaBean 屬性的普通結(jié)果
  • association – 一個(gè)復(fù)雜類(lèi)型的關(guān)聯(lián);許多結(jié)果將包裝成這種類(lèi)型
    • 嵌套結(jié)果映射 – 關(guān)聯(lián)可以指定為一個(gè) resultMap 元素,或者引用一個(gè)
  • collection – 一個(gè)復(fù)雜類(lèi)型的集合
    • 嵌套結(jié)果映射 – 集合可以指定為一個(gè) resultMap 元素,或者引用一個(gè)
  • discriminator* – 使用結(jié)果值來(lái)決定使用哪個(gè) resultMap
    • case – 基于某些值的結(jié)果映射
      • 嵌套結(jié)果映射 – 一個(gè) case 也是一個(gè)映射它本身的結(jié)果,因此可以包含很多相 同的元素,或者它可以參照一個(gè)外部的 resultMap。
ResultMap 屬性描述
屬性 描述
id 當(dāng)前命名空間中的一個(gè)唯一標(biāo)識(shí),用于標(biāo)識(shí)一個(gè)result map.
type 類(lèi)的完全限定名, 或者一個(gè)類(lèi)型別名 (內(nèi)置的別名可以參考上面的表格).
autoMapping 如果設(shè)置這個(gè)屬性,MyBatis將會(huì)為這個(gè)ResultMap開(kāi)啟或者關(guān)閉自動(dòng)映射。這個(gè)屬性會(huì)覆蓋全局的屬性 autoMappingBehavior。默認(rèn)值為:unset。

id & result

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

id 和 result 都將一個(gè)列的值映射到一個(gè)簡(jiǎn)單數(shù)據(jù)類(lèi)型(字符串,整型,雙精度浮點(diǎn)數(shù),日期等)的屬性或字段。
id 表示的結(jié)果將是對(duì)象的標(biāo)識(shí)屬性,這會(huì)在比較對(duì)象實(shí)例時(shí)用到。 這樣可以提高整體的性能,尤其是緩存和嵌套結(jié)果映射(也就是聯(lián)合映射)的時(shí)候。

Id 和 Result 的屬性
屬性 描述
property 映射到列結(jié)果的字段或?qū)傩浴H绻脕?lái)匹配的 JavaBeans 存在給定名字的屬性,那么它將會(huì)被使用。否則 MyBatis 將會(huì)尋找給定名稱(chēng) property 的字段。 無(wú)論是哪一種情形,你都可以使用通常的點(diǎn)式分隔形式進(jìn)行復(fù)雜屬性導(dǎo)航。比如,你可以這樣映射一些簡(jiǎn)單的東西: “username” ,或者映射到一些復(fù)雜的東西: “address.street.number” 。
column 數(shù)據(jù)庫(kù)中的列名,或者是列的別名。一般情況下,這和 傳遞給 resultSet.getString(columnName) 方法的參數(shù)一樣。
javaType 一個(gè) Java 類(lèi)的完全限定名,或一個(gè)類(lèi)型別名(參考上面內(nèi)建類(lèi)型別名 的列表) 。如果你映射到一個(gè) JavaBean,MyBatis 通常可以斷定類(lèi)型。 然而,如果你映射到的是 HashMap,那么你應(yīng)該明確地指定 javaType 來(lái)保證期望的行為。
jdbcType JDBC 類(lèi)型,所支持的 JDBC 類(lèi)型參見(jiàn)這個(gè)表格之后的“支持的 JDBC 類(lèi)型”。 只需要在可能執(zhí)行插入、更新和刪除的允許空值的列上指定 JDBC 類(lèi)型。這是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 編程,你需要對(duì)可能為 null 的值指定這個(gè)類(lèi)型。
typeHandler 我們?cè)谇懊嬗懻撨^(guò)的默認(rèn)類(lèi)型處理器。使用這個(gè)屬性,你可以覆蓋默認(rèn)的類(lèi)型處理器。這個(gè)屬性值是一個(gè)類(lèi)型處理 器實(shí)現(xiàn)類(lèi)的完全限定名,或者是類(lèi)型別名。

構(gòu)造方法(Constructor)

constructor 元素可以使構(gòu)造方法注入允許你在初始化時(shí)為類(lèi)設(shè)置屬性的值,而不用暴露出公有方法。
例如如下構(gòu)造方法:

public class User {
   //...
   public User(Integer id, String username, int age) {
     //...
  }
//...
}

可以構(gòu)建如下constructor元素:

<constructor>
   <idArg column="id" javaType="int"/>
   <arg column="username" javaType="String"/>
   <arg column="age" javaType="_int"/>
</constructor>

對(duì)于帶有多個(gè)形參的構(gòu)造方法,可以在指定參數(shù)名稱(chēng)的前提下,以任意順序編寫(xiě) arg 元素。 為了通過(guò)名稱(chēng)來(lái)引用構(gòu)造方法參數(shù),你可以添加 @Param 注解,或者使用 '-parameters' 編譯選項(xiàng)并啟用 useActualParamName 選項(xiàng)(默認(rèn)開(kāi)啟)來(lái)編譯項(xiàng)目。 下面的例子對(duì)于同一個(gè)構(gòu)造方法依然是有效的,盡管第二和第三個(gè)形參順序與構(gòu)造方法中聲明的順序不匹配。

<constructor>
   <idArg column="id" javaType="int" name="id" />
   <arg column="age" javaType="_int" name="age" />
   <arg column="username" javaType="String" name="username" />
</constructor>

如果類(lèi)中存在名稱(chēng)和類(lèi)型相同的屬性,那么可以省略 javaType 。

屬性規(guī)則
屬性 描述
column 數(shù)據(jù)庫(kù)中的列名,或者是列的別名。一般情況下,這和 傳遞給 resultSet.getString(columnName) 方法的參數(shù)一樣。
javaType 一個(gè) Java 類(lèi)的完全限定名,或一個(gè)類(lèi)型別名(參考上面內(nèi)建類(lèi)型別名的列表)。 如果你映射到一個(gè) JavaBean,MyBatis 通常可以斷定類(lèi)型。然而,如 果你映射到的是 HashMap,那么你應(yīng)該明確地指定 javaType 來(lái)保證期望的 行為。
jdbcType JDBC 類(lèi)型,所支持的 JDBC 類(lèi)型參見(jiàn)這個(gè)表格之前的“支持的 JDBC 類(lèi)型”。 只需要在可能執(zhí)行插入、更新和刪除的允許空值的列上指定 JDBC 類(lèi)型。這是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 編程,你需要對(duì)可能為 null 的值指定這個(gè)類(lèi)型。
typeHandler 我們?cè)谇懊嬗懻撨^(guò)的默認(rèn)類(lèi)型處理器。使用這個(gè)屬性,你可以覆蓋默 認(rèn)的類(lèi)型處理器。這個(gè)屬性值是一個(gè)類(lèi)型處理 器實(shí)現(xiàn)類(lèi)的完全限定名,或者是類(lèi)型別名。
select 用于加載復(fù)雜類(lèi)型屬性的映射語(yǔ)句的 ID,它會(huì)從 column 屬性中指定的列檢索數(shù)據(jù),作為參數(shù)傳遞給此 select 語(yǔ)句。具體請(qǐng)參考 Association 標(biāo)簽。
resultMap ResultMap 的 ID,可以將嵌套的結(jié)果集映射到一個(gè)合適的對(duì)象樹(shù)中,功能和 select 屬性相似,它可以實(shí)現(xiàn)將多表連接操作的結(jié)果映射成一個(gè)單一的ResultSet。這樣的ResultSet將會(huì)將包含重復(fù)或部分?jǐn)?shù)據(jù)重復(fù)的結(jié)果集正確的映射到嵌套的對(duì)象樹(shù)中。為了實(shí)現(xiàn)它, MyBatis允許你 “串聯(lián)” ResultMap,以便解決嵌套結(jié)果集的問(wèn)題。想了解更多內(nèi)容,請(qǐng)參考下面的Association元素。
name 構(gòu)造方法形參的名字。從3.4.3版本開(kāi)始,通過(guò)指定具體的名字,你可以以任意順序?qū)懭隺rg元素。參看上面的解釋。

關(guān)聯(lián)(association)

<association property="author" column="blog_author_id" javaType="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
</association>

關(guān)聯(lián)元素處理“有一個(gè)”類(lèi)型的關(guān)系。
MyBatis 有兩種不同的方式加載關(guān)聯(lián):

  • 嵌套查詢(xún):通過(guò)執(zhí)行另外一個(gè) SQL 映射語(yǔ)句來(lái)返回預(yù)期的復(fù)雜類(lèi)型。
  • 嵌套結(jié)果:使用嵌套結(jié)果映射來(lái)處理重復(fù)的聯(lián)合結(jié)果的子集。
association的屬性描述
屬性 描述
property 映射到列結(jié)果的字段或?qū)傩浴H绻脕?lái)匹配的 JavaBeans 存在給定名字的屬性,那么它將會(huì)被使用。 否則 MyBatis 將會(huì)尋找與給定名稱(chēng)相同的字段。 這兩種情形你可以使用通常點(diǎn)式的復(fù)雜屬性導(dǎo)航。比如,你可以這樣映射 一 些 東 西 :“ username ”, 或 者 映 射 到 一 些 復(fù) 雜 的 東 西 : “address.street.number” 。
javaType 一個(gè) Java 類(lèi)的完全限定名,或一個(gè)類(lèi)型別名(參考上面內(nèi)建類(lèi)型別名的列 表) 。如果你映射到一個(gè) JavaBean,MyBatis 通常可以斷定類(lèi)型。然而,如 javaType 果你映射到的是 HashMap,那么你應(yīng)該明確地指定 javaType 來(lái)保證所需的 行為。
jdbcType 在這個(gè)表格之前的所支持的 JDBC 類(lèi)型列表中的類(lèi)型。JDBC 類(lèi)型是僅僅 需要對(duì)插入, 更新和刪除操作可能為空的列進(jìn)行處理。這是 JDBC 的需要, jdbcType 而不是 MyBatis 的。如果你直接使用 JDBC 編程,你需要指定這個(gè)類(lèi)型-但 僅僅對(duì)可能為空的值。
typeHandler 我們?cè)谇懊嬗懻撨^(guò)默認(rèn)的類(lèi)型處理器。使用這個(gè)屬性,你可以覆蓋默認(rèn)的 typeHandler 類(lèi)型處理器。 這個(gè)屬性值是類(lèi)的完全限定名或者是一個(gè)類(lèi)型處理器的實(shí)現(xiàn), 或者是類(lèi)型別名。
association的嵌套查詢(xún)
屬性 描述
column 來(lái)自數(shù)據(jù)庫(kù)的列名,或重命名的列標(biāo)簽。這和通常傳遞給 resultSet.getString(columnName)方法的字符串是相同的。 column 注 意 : 要 處 理 復(fù) 合 主 鍵 , 你 可 以 指 定 多 個(gè) 列 名 通 過(guò) column= ” {prop1=col1,prop2=col2} ” 這種語(yǔ)法來(lái)傳遞給嵌套查詢(xún)語(yǔ) 句。這會(huì)引起 prop1 和 prop2 以參數(shù)對(duì)象形式來(lái)設(shè)置給目標(biāo)嵌套查詢(xún)語(yǔ)句。
select 另外一個(gè)映射語(yǔ)句的 ID,可以加載這個(gè)屬性映射需要的復(fù)雜類(lèi)型。獲取的 在列屬性中指定的列的值將被傳遞給目標(biāo) select 語(yǔ)句作為參數(shù)。表格后面 有一個(gè)詳細(xì)的示例。 select 注 意 : 要 處 理 復(fù) 合 主 鍵 , 你 可 以 指 定 多 個(gè) 列 名 通 過(guò) column= ” {prop1=col1,prop2=col2} ” 這種語(yǔ)法來(lái)傳遞給嵌套查詢(xún)語(yǔ) 句。這會(huì)引起 prop1 和 prop2 以參數(shù)對(duì)象形式來(lái)設(shè)置給目標(biāo)嵌套查詢(xún)語(yǔ)句。
fetchType 可選的。有效值為 lazy和eager。 如果使用了,它將取代全局配置參數(shù)lazyLoadingEnabled。

例如:

<resultMap id="blogResult" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectAuthor" resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>
associate的嵌套結(jié)果
屬性 描述
resultMap 這是結(jié)果映射的 ID,可以映射關(guān)聯(lián)的嵌套結(jié)果到一個(gè)合適的對(duì)象圖中。這 是一種替代方法來(lái)調(diào)用另外一個(gè)查詢(xún)語(yǔ)句。這允許你聯(lián)合多個(gè)表來(lái)合成到 resultMap 一個(gè)單獨(dú)的結(jié)果集。這樣的結(jié)果集可能包含重復(fù),數(shù)據(jù)的重復(fù)組需要被分解,合理映射到一個(gè)嵌套的對(duì)象圖。為了使它變得容易,MyBatis讓你“鏈接”結(jié)果映射,來(lái)處理嵌套結(jié)果。
columnPrefix 當(dāng)連接多表時(shí),你將不得不使用列別名來(lái)避免ResultSet中的重復(fù)列名。指定columnPrefix允許你映射列名到一個(gè)外部的結(jié)果集中。
notNullColumn 默認(rèn)情況下,子對(duì)象僅在至少一個(gè)列映射到其屬性非空時(shí)才創(chuàng)建。 通過(guò)對(duì)這個(gè)屬性指定非空的列將改變默認(rèn)行為,這樣做之后Mybatis將僅在這些列非空時(shí)才創(chuàng)建一個(gè)子對(duì)象。 可以指定多個(gè)列名,使用逗號(hào)分隔。默認(rèn)值:未設(shè)置(unset)。
autoMapping 如果使用了,當(dāng)映射結(jié)果到當(dāng)前屬性時(shí),Mybatis將啟用或者禁用自動(dòng)映射。 該屬性覆蓋全局的自動(dòng)映射行為。 注意它對(duì)外部結(jié)果集無(wú)影響,所以在select or resultMap屬性中這個(gè)是毫無(wú)意義的。 默認(rèn)值:未設(shè)置(unset)。

以下例子講博客表和作者表聯(lián)合:

<select id="selectBlog" resultMap="blogResult">
  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
  from Blog B left outer join Author A on B.author_id = A.id
  where B.id = #{id}
</select>

將上面的結(jié)果映射

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>

<resultMap id="authorResult" type="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"/>
</resultMap>

上面的例子的Author結(jié)果可以重用,如果不需要重用,僅僅引用所有的結(jié)果映射合到一個(gè)單獨(dú)描述的結(jié)果映射中。可以做如下例子的結(jié)果映射:

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" 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"/>
  </association>
</resultMap>

如果需要有一個(gè)co-author,select語(yǔ)句為:

<select id="selectBlog" resultMap="blogResult">
  select
    B.id            as blog_id,
    B.title         as blog_title,
    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,
    CA.id           as co_author_id,
    CA.username     as co_author_username,
    CA.password     as co_author_password,
    CA.email        as co_author_email,
    CA.bio          as co_author_bio
  from Blog B
  left outer join Author A on B.author_id = A.id
  left outer join Author CA on B.co_author_id = CA.id
  where B.id = #{id}
</select>

再次調(diào)用的Author的resultMap定義和之前一樣。僅僅是結(jié)果中的列名不同。需要指定columnPrefix去重用映射co-author結(jié)果的resultMap

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author"
    resultMap="authorResult" />
  <association property="coAuthor"
    resultMap="authorResult"
    columnPrefix="co_" />
</resultMap>

association元素用來(lái)解決“有一個(gè)類(lèi)”關(guān)聯(lián),“有很多個(gè)”關(guān)聯(lián),就是用集合(collection)元素解決的。

集合(collection)

簡(jiǎn)單例子:

<collection property="posts" ofType="domain.blog.Post">
  <id property="id" column="post_id"/>
  <result property="subject" column="post_subject"/>
  <result property="body" column="post_body"/>
</collection>

collection和association很多部分相同,以下僅介紹有哪些不同。

根據(jù)association中的例子,一個(gè)博客有一個(gè)作者,有很多文章:

private List<Post> posts;
collection的嵌套查詢(xún)

嵌套查詢(xún)?yōu)椴┛图虞d文章。

<resultMap id="blogResult" type="Blog">
  <?--在 Post 類(lèi)型的 ArrayList 中的 posts 的集合。ArrayList屬性可以省略-->
  <collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectPostsForBlog" resultType="Post">
  SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>
collection的嵌套結(jié)果

collection和association使用方法相同,除了應(yīng)用了一個(gè)“ofType”屬性。
SQL:

<select id="selectBlog" resultMap="blogResult">
  select
  B.id as blog_id,
  B.title as blog_title,
  B.author_id as blog_author_id,
  P.id as post_id,
  P.subject as post_subject,
  P.body as post_body,
  from Blog B
  left outer join Post P on B.id = P.blog_id
  where B.id = #{id}
</select>

映射:

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <result property="body" column="post_body"/>
  </collection>
</resultMap>

需要對(duì)結(jié)果進(jìn)行重用,可以抽離成resultMap:

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post" resultMap="blogPostResult" columnPrefix="post_"/>
</resultMap>

<resultMap id="blogPostResult" type="Post">
  <id property="id" column="id"/>
  <result property="subject" column="subject"/>
  <result property="body" column="body"/>
</resultMap>

鑒別器(discriminator)

簡(jiǎn)單例子:

<discriminator javaType="int" column="draft">
  <case value="1" resultType="DraftPost"/>
</discriminator>

鑒別器用于單獨(dú)的數(shù)據(jù)庫(kù)返回不同的數(shù)據(jù)類(lèi)型的結(jié)果集。指定了 column 和 javaType 屬性。 列是 MyBatis 查找比較值的地方。 JavaType 是需要被用來(lái)保證等價(jià)測(cè)試的合適類(lèi)型(盡管字符串在很多情形下都會(huì)有用):

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultMap="carResult"/>
    <case value="2" resultMap="truckResult"/>
    <case value="3" resultMap="vanResult"/>
    <case value="4" resultMap="suvResult"/>
  </discriminator>
</resultMap>

在這個(gè)示例中, MyBatis 會(huì)從結(jié)果集中得到每條記錄, 然后比較它的 vehicle 類(lèi)型的值。 如果它匹配任何一個(gè)鑒別器的實(shí)例,那么就使用這個(gè)實(shí)例指定的結(jié)果映射。換句話說(shuō),這樣 做完全是剩余的結(jié)果映射被忽略(除非它被擴(kuò)展,這在第二個(gè)示例中討論) 。如果沒(méi)有任何 一個(gè)實(shí)例相匹配,那么 MyBatis 僅僅使用鑒別器塊外定義的結(jié)果映射。所以,如果 carResult 按如下聲明:

<resultMap id="carResult" type="Car">
  <result property="doorCount" column="door_count" />
</resultMap>

那么只有 doorCount 屬性會(huì)被加載。這步完成后完整地允許鑒別器實(shí)例的獨(dú)立組,盡管 和父結(jié)果映射可能沒(méi)有什么關(guān)系。這種情況下,我們當(dāng)然知道 cars 和 vehicles 之間有關(guān)系, 如 Car 是一個(gè) Vehicle 實(shí)例。以下方式使vehicleResult 和 carResult 的屬性都會(huì)被加載:

<resultMap id="carResult" type="Car" extends="vehicleResult">
  <result property="doorCount" column="door_count" />
</resultMap>

可以按如下方式進(jìn)行嵌套映射:

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultType="carResult">
      <result property="doorCount" column="door_count" />
    </case>
    <case value="2" resultType="truckResult">
      <result property="boxSize" column="box_size" />
      <result property="extendedCab" column="extended_cab" />
    </case>
    <case value="3" resultType="vanResult">
      <result property="powerSlidingDoor" column="power_sliding_door" />
    </case>
    <case value="4" resultType="suvResult">
      <result property="allWheelDrive" column="all_wheel_drive" />
    </case>
  </discriminator>
</resultMap>

自動(dòng)映射

當(dāng)自動(dòng)映射查詢(xún)結(jié)果時(shí),MyBatis會(huì)獲取sql返回的列名并在java類(lèi)中查找相同名字的屬性(忽略大小寫(xiě))。 這意味著如果Mybatis發(fā)現(xiàn)了ID列和id屬性,Mybatis會(huì)將ID的值賦給id。

通常數(shù)據(jù)庫(kù)列使用大寫(xiě)單詞命名,單詞間用下劃線分隔;而java屬性一般遵循駝峰命名法。 為了在這兩種命名方式之間啟用自動(dòng)映射,需要將 mapUnderscoreToCamelCase設(shè)置為true。

自動(dòng)映射在特定的result map下也能工作。在這種情況下,對(duì)于每一個(gè)result map,所有的ResultSet提供的列, 如果沒(méi)有被手工映射,則將被自動(dòng)映射。自動(dòng)映射處理完畢后手工映射才會(huì)被處理。 在接下來(lái)的例子中, id 和 userName列將被自動(dòng)映射, hashed_password 列將根據(jù)配置映射:

<select id="selectUsers" resultMap="userResultMap">
  select
    user_id             as "id",
    user_name           as "userName",
    hashed_password
  from some_table
  where id = #{id}
</select>
<resultMap id="userResultMap" type="User">
  <result property="password" column="hashed_password"/>
</resultMap>

有三種映射等級(jí),默認(rèn)值是PARTIAL

  • NONE - 禁用自動(dòng)映射。僅設(shè)置手動(dòng)映射屬性。
  • PARTIAL - 將自動(dòng)映射結(jié)果除了那些有內(nèi)部定義內(nèi)嵌結(jié)果映射的(joins).
  • FULL - 自動(dòng)映射所有。

通過(guò)添加autoMapping屬性可以忽略自動(dòng)映射等級(jí)配置,你可以啟用或者禁用自動(dòng)映射指定的ResultMap。

<resultMap id="userResultMap" type="User" autoMapping="false">
  <result property="password" column="hashed_password"/>
</resultMap>

緩存

默認(rèn)情況下是沒(méi)有開(kāi)啟緩存的,除了局部的 session 緩存。要開(kāi)啟二級(jí)緩存,你需要在你的 SQL 映射文件中添加一行:

<cache/>

作用為:

  • 映射語(yǔ)句文件中的所有 select 語(yǔ)句將會(huì)被緩存。
  • 映射語(yǔ)句文件中的所有 insert,update 和 delete 語(yǔ)句會(huì)刷新緩存。
  • 緩存會(huì)使用 Least Recently Used(LRU,最近最少使用的)算法來(lái)收回。
  • 根據(jù)時(shí)間表(比如 no Flush Interval,沒(méi)有刷新間隔), 緩存不會(huì)以任何時(shí)間順序 來(lái)刷新。
  • 緩存會(huì)存儲(chǔ)列表集合或?qū)ο?無(wú)論查詢(xún)方法返回什么)的 1024 個(gè)引用。
  • 緩存會(huì)被視為是 read/write(可讀/可寫(xiě))的緩存,意味著對(duì)象檢索不是共享的,而 且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。

所有的這些屬性都可以通過(guò)緩存元素的屬性來(lái)修改。比如:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

這個(gè)更高級(jí)的配置創(chuàng)建了一個(gè) FIFO 緩存,并每隔 60 秒刷新,存數(shù)結(jié)果對(duì)象或列表的 512 個(gè)引用,而且返回的對(duì)象被認(rèn)為是只讀的,因此在不同線程中的調(diào)用者之間修改它們會(huì) 導(dǎo)致沖突。

可用的收回策略有:

  • LRU – 最近最少使用的:移除最長(zhǎng)時(shí)間不被使用的對(duì)象。
  • FIFO – 先進(jìn)先出:按對(duì)象進(jìn)入緩存的順序來(lái)移除它們。
  • SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對(duì)象。
  • WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對(duì)象。
    默認(rèn)的是 LRU。

flushInterval(刷新間隔)可以被設(shè)置為任意的正整數(shù),而且它們代表一個(gè)合理的毫秒 形式的時(shí)間段。默認(rèn)情況是不設(shè)置,也就是沒(méi)有刷新間隔,緩存僅僅調(diào)用語(yǔ)句時(shí)刷新。

size(引用數(shù)目)可以被設(shè)置為任意正整數(shù),要記住你緩存的對(duì)象數(shù)目和你運(yùn)行環(huán)境的 可用內(nèi)存資源數(shù)目。默認(rèn)值是 1024。

readOnly(只讀)屬性可以被設(shè)置為 true 或 false。只讀的緩存會(huì)給所有調(diào)用者返回緩 存對(duì)象的相同實(shí)例。因此這些對(duì)象不能被修改。這提供了很重要的性能優(yōu)勢(shì)。可讀寫(xiě)的緩存 會(huì)返回緩存對(duì)象的拷貝(通過(guò)序列化) 。這會(huì)慢一些,但是安全,因此默認(rèn)是 false。

自定義緩存

可以通過(guò)實(shí)現(xiàn)自定義緩存或?yàn)槠渌谌骄彺娣桨竸?chuàng)建適配器來(lái)完全覆蓋緩存行為。

<cache  type="com.domain.something.MyCustomCache"/>

這個(gè)示例展 示了如何使用一個(gè)自定義的緩存實(shí)現(xiàn)。type屬性指定的類(lèi)必須實(shí)現(xiàn) org.mybatis.cache.Cache 接口。

public interface Cache {
  String getId();
  int getSize();
  void putObject(Object key, Object value);
  Object getObject(Object key);
  boolean hasKey(Object key);
  Object removeObject(Object key);
  void clear();
}

要配置你的緩存, 僅僅添加公有的 JavaBeans 屬性來(lái)配置緩存實(shí)現(xiàn), 然后通過(guò) cache 元素來(lái)傳遞屬性, 比如, 下面代碼會(huì)在你的緩存實(shí)現(xiàn)中調(diào)用一個(gè)稱(chēng)為 “setCacheFile(String file)” 的方法:

<cache type="com.domain.something.MyCustomCache">
  <property name="cacheFile" value="/tmp/my-custom-cache.tmp"/>
</cache>

可以在所有屬性設(shè)置完畢以后可以調(diào)用一個(gè)初始化方法。如果你想要使用這個(gè)特性,請(qǐng)?jiān)谀愕淖远x緩存類(lèi)里實(shí)現(xiàn) org.apache.ibatis.builder.InitializingObject接口。

public interface InitializingObject {
  void initialize() throws Exception;
}

It's important to remember that a cache configuration and the cache instance are bound to the namespace of the SQL Map file. Thus, all statements in the same namespace as the cache are bound by it. Statements can modify how they interact with the cache, or exclude themselves completely by using two simple attributes on a statement-by-statement basis. By default, statements are configured like this:

<select ... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>

不能明確地以這種方式來(lái)配置一條語(yǔ)句。相反,如果你想改變默認(rèn)的行為,只能設(shè)置 flushCache 和 useCache 屬性。比如,在一些情況下你也許想排除 從緩存中查詢(xún)特定語(yǔ)句結(jié)果,或者你也許想要一個(gè)查詢(xún)語(yǔ)句來(lái)刷新緩存。相似地,你也許有 一些更新語(yǔ)句依靠執(zhí)行而不需要刷新緩存。

參照緩存

回想一下上一節(jié)內(nèi)容, 這個(gè)特殊命名空間的唯一緩存會(huì)被使用或者刷新相同命名空間內(nèi) 的語(yǔ)句。也許將來(lái)的某個(gè)時(shí)候,你會(huì)想在命名空間中共享相同的緩存配置和實(shí)例。在這樣的 情況下你可以使用 cache-ref 元素來(lái)引用另外一個(gè)緩存。

<cache-ref  namespace="com.someone.application.data.SomeMapper"/>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,688評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,654評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,456評(píng)論 6 406
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,955評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,195評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,608評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,802評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,048評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,422評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,673評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,424評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,762評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容

  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的...
    笨鳥(niǎo)慢飛閱讀 5,560評(píng)論 0 4
  • MyBatis 理論篇 [TOC] 什么是MyBatis ?MyBatis是支持普通SQL查詢(xún),存儲(chǔ)過(guò)程和高級(jí)映射...
    有_味閱讀 2,927評(píng)論 0 26
  • 1 Mybatis入門(mén) 1.1 單獨(dú)使用jdbc編程問(wèn)題總結(jié) 1.1.1 jdbc程序 上邊使...
    哇哈哈E閱讀 3,318評(píng)論 0 38
  • MyBatis 真正的力量是在映射語(yǔ)句中。這里是奇跡發(fā)生的地方。對(duì)于所有的力量,SQL 映射的 XML 文件是相當(dāng)...
    zhDoveLie閱讀 820評(píng)論 1 0
  • 正上課講在興頭上,發(fā)現(xiàn)學(xué)生們眼光都朝教室外望去。原來(lái),門(mén)口站著一位六七十歲的老年人,應(yīng)該是某位學(xué)生的奶奶。看我停下...
    媽媽老師是超人閱讀 285評(píng)論 0 1