您好,登錄后才能下訂單哦!
這篇文章主要介紹“基于Mybatis的配置文件的原理”,在日常操作中,相信很多人在基于Mybatis的配置文件的原理問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”基于Mybatis的配置文件的原理”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
我們通過閱讀其源碼來逐步了解內(nèi)部實現(xiàn)原理。
// Mybatis 通過SqlSessionFactory獲取SqlSession, 然后才能通過SqlSession與數(shù)據(jù)庫進行交互 private static SqlSessionFactory getSessionFactory() { SqlSessionFactory sessionFactory = null; String resource = "configuration.xml"; try { sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource)); } catch (IOException e) { e.printStackTrace(); } return sessionFactory; }
查看其源碼:
/** * Copyright 2009-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.session; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.Properties; import org.apache.ibatis.builder.xml.XMLConfigBuilder; import org.apache.ibatis.exceptions.ExceptionFactory; import org.apache.ibatis.executor.ErrorContext; import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory; /** * Builds {@link SqlSession} instances. * * @author Clinton Begin */ public class SqlSessionFactoryBuilder { public SqlSessionFactory build(Reader reader) { return build(reader, null, null); } public SqlSessionFactory build(Reader reader, String environment) { return build(reader, environment, null); } public SqlSessionFactory build(Reader reader, Properties properties) { return build(reader, null, properties); } public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null); } public SqlSessionFactory build(InputStream inputStream, String environment) { return build(inputStream, environment, null); } public SqlSessionFactory build(InputStream inputStream, Properties properties) { return build(inputStream, null, properties); } public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } }
在這個類中,支持多種構(gòu)造SqlSessionFactory的方法??梢灾粋魅雖ybatis配置文件,也可以同時傳入properties配置文件替代mybatis配置文件中的<properties>元素標(biāo)簽,另外也支持傳入環(huán)境參數(shù)envirmont參數(shù)。
public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } }
這里創(chuàng)建了一個XMLConfigBuilder類實例,通過他來對mybatis配置文件(一個xml配置文件)進行解析。
public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; } private void parseConfiguration(XNode root) { try { Properties settings = settingsAsPropertiess(root.evalNode("settings")); //issue #117 read properties first propertiesElement(root.evalNode("properties")); loadCustomVfs(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
從這里看出,配置文件是以configuration為根節(jié)點,在根節(jié)點之下有多個子節(jié)點,它們分別為:settings、properties、typeAliases、plugins、objectFactory、objectWrapperFactory、environments、databaseIdProvider、typeHandlers、mappers。
MyBatis
的配置文件包含了影響MyBatis行為甚深的設(shè)置(settings)和屬性(properties)信息。文檔的頂層結(jié)果如下:
configuration
配置
properties
屬性
setting
設(shè)置
typeAliases
類型命名
typeHandlers
類型處理器
objectFactory
對象工廠
plugins
插件
environments
環(huán)境
environment
環(huán)境變量
transactionManager
事務(wù)管理器
dataSource
數(shù)據(jù)源
databaseIdProyider
數(shù)據(jù)庫廠商標(biāo)識
mappers
映射
屬性都是可外部配置且可動態(tài)替換的,既可以在典型的Java屬性文件中配置,亦可通過properties元素的子元素來傳遞。
例如:
<!-- mybatis的核心配置文件 1.數(shù)據(jù)庫的連接信息(連接池) --> <properties resource="jdbc.properties"></properties>
其中的屬性就可以在整個配置文件中使用來替換需要動態(tài)配置的屬性值。
比如:
<!-- 默認(rèn)連接池 --> <dataSource type="POOLED"> <property name="driver" value="${driverClass}"/> <property name="url" value="${url}"/> <property name="username" value="${userid}"/> <property name="password" value="${password}"/> </dataSource>
properties
屬性:將數(shù)據(jù)庫連接參數(shù)單獨配置在jdbc.properties中,只需要在mybatis.xml文件中加載jdbc.properties的屬性值。 在mybatis.xml中就不需要對數(shù)據(jù)庫連接參數(shù)硬編碼(硬編碼是指將可變變量用一個固定值來代替的方法)。在properties 元素體內(nèi)定義的屬性首先被讀取。然后會讀取properties元素中resource或url加載屬性,它會覆蓋已讀取的同名屬性。
注意:如果在properties標(biāo)簽里面定義的屬性被${}所引用了,對#{}不管用。那么它不會讀取parameterType里面的參數(shù)值。比如properties里面定義了id屬性,值為40,在映射文件中引用該值,${id}那么我從parameterType里面?zhèn)髦禃r,不管我傳基本類型還是引用類型進去都不會覆蓋這個${id}值。始終都會讀取40.
屬性也可以被傳遞到SqlSessionBuilder.build()方法中。
例如:
SqlSessionFactoryBuilder
源碼:
public SqlSessionFactory build(Reader reader, Properties properties) { return build(reader, null, properties); } public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } }
類型別名是為Java類型設(shè)置一個短的名字。它只和XML配置有關(guān),存在意義僅在于用來減少類完全限定名的冗余。
例如:
<!-- 給類定義別名 --> <typeAliases> <typeAlias type="cn.et.lesson02.annotion.Food" alias="food"/> <typeAlias alias="Author" type="domain.blog.Author"/> <typeAlias alias="Blog" type="domain.blog.Blog"/> </typeAliases>
當(dāng)這樣配置時,Blog可以用在任何使用domain.blog.Blog的地方。
也可以指定一個包名,MyBatis會在包名下面搜索需要的Java Bean
比如:
<typeAliases> <package name="domain.blog"/> </typeAliases>
每一個包domain.blog中的Java Bean,在沒有注解的情況下,會使用Bean的首字母小寫的非限定類名來作為它的別名。比如domain.blog.Author的別名為author;若有注解,則別名為其注解值。
看下面的例子:
@Alias("author") public class Author { ... }
mapper
標(biāo)簽(映射配置):加載映射文件
<mappers> <!-- 通過resource加載單個映射文件 加載單個類路徑下的映射文件 使用相對于類路徑的資源: --> <mapper resource="cn/et/lesson01/FoodMapper.xml"/> <!-- 使用類路徑加載單個映射文件 <mapper url="cn.domarvel.dao.UserMapper"/> 注意:此種方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個目錄中。并且還有一個前提是:使用的是mapper代理方法 --> <!-- 自動批量加載指定包下的所有Mapper接口配置文件 <package name="cn.domarvel.dao"/> 注意:此種方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個目錄中。并且還有一個前提是:使用的是mapper代理方法 --> </mappers>
MyBatis的真正強大在于他的映射語句,也是它的魔力所在,由于它的異常強大,映射器的XML文件就顯得相對簡單。如果拿它跟具有相同功能的JDBC代碼進行對比,你會立即發(fā)現(xiàn)省掉了將近95%的代碼。MyBatis就是針對SQL構(gòu)建的,并且比普通的方法做的更好。
mapper
標(biāo)簽:映射文件的根節(jié)點,在根節(jié)點中支持九個元素。
namespace是用于綁定Dao接口的,當(dāng)你的namespace綁定接口后,你可以不用寫接口實現(xiàn)類,mybatis會通過該綁定自動幫你找到對應(yīng)要執(zhí)行的SQL語句
注意:接口中的方法與映射文件中的SQL語句的ID一一對應(yīng)
<mapper namespace="a"> </mapper> <mapper namespace="cn.et.lesson02.xml.FoodMapper" > </mapper>
SQL映射文件有很少的幾個頂級元素(按照它們應(yīng)該被定義的順序):
cache
:給定命名空間的緩存配置
cache-ref
:其命名空間緩存配置的引用。
resultMap
:是最復(fù)雜也是最強大的元素,用來描述如何從數(shù)據(jù)庫結(jié)果集中來加載對象。
parameterMap
:已廢棄,老式風(fēng)格的參數(shù)映射。內(nèi)聯(lián)參數(shù)是首選,這個元素可能在將來被移除,這里不會記錄。
sql
:可被其他語句引用的可重用語句塊。
insert
:映射插入語句
update
:映射更新語句
delete
:映射更新語句
select
:映射查詢語句
查詢語句是MyBatis中最常用的元素之一,光能把數(shù)據(jù)存到數(shù)據(jù)庫中價值并不大,如果還能重新取出來才有用,多數(shù)應(yīng)用也都是查詢比修改要頻繁。對每個插入、更新或刪除操作,通常對應(yīng)多個查詢操作。這是MyBatis的基本原則之一,也是將焦點和努力放在查詢和結(jié)果映射的原因。簡單查詢的select元素時非常簡單的。
比如
<select id="selectPerson" parameterType="int" resultType="hashmap"> SELECT * FROM PERSON WHERE ID = #{id} </select>
這個語句被稱作selectPerson,接收一個int(或Integer)類型的參數(shù),并返回一個HashMap類型的對象,其中的鍵是列名,值便是結(jié)果行中的對應(yīng)值。
注意參數(shù)符號:#{id}
select元素有很多屬性允許你配置,來決定每條語句的作用細(xì)節(jié)。
SELECT多條件查詢
parameterType用于傳遞參數(shù)多參數(shù)可以使用傳入對象以及map的方式傳遞多個參數(shù)。
#{}表示傳遞的參數(shù)值 類同jdbc的? ${}表示直接將參數(shù)值替換類同'%值%'
比如:
<select id=“selectPerson” parameterType=“map” resultType=“person”> SELECT * FROM PERSON WHERE ID = #{id} and name like ‘%${name}%' </select>
Map中必須存在id和name的鍵值對
SELECT調(diào)用存儲過程
創(chuàng)建存儲過程prg_add(p1 in number,p2 in number,p3 out number)
Mybatis映射文件中使用select調(diào)用存儲過程
<select id=“prgAdd" statementType="CALLABLE"> <![CDATA[ {call pro_hello ( #{p1,mode=IN,jdbcType=NUMBER}, #{p2,mode=IN,jdbcType=NUMBER}, #{result,mode=OUT,jdbcType=NUMBER})} ]]> </select>
測試調(diào)用過程
Map<String, String> param = new HashMap<String, String>(); param.put(“p1”, 1); param.put(“p2”, 2); String returnValue = (String) session.selectOne(" prgAdd ", param); System.out.println("result=" + param.get("result")); System.out.println("returnValue=" + returnValue);
數(shù)據(jù)更變語句insert、update和delete的實現(xiàn)非常接近
<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">
parameterType
:入?yún)⒌娜薅惷蝾愋蛣e名
keyColumn
:設(shè)置數(shù)據(jù)表自動生成的主鍵名。對特定數(shù)據(jù)庫(如PostgreSQL),若自動生成的主鍵不是第一個字段則必須設(shè)置
keyProperty
:默認(rèn)值unset,用于設(shè)置getGeneratedKeys方法或selectKey子元素返回值將賦值到領(lǐng)域模型的哪個屬性中
useGeneratedKey
:取值范圍true|false(默認(rèn)值)設(shè)置是否使用JDBC的getGenereatedKeys方法獲取主鍵并賦值到keyProperty設(shè)置的領(lǐng)域模型屬性中。
MySQL和SQLServer執(zhí)行auto-generated key field,因此當(dāng)數(shù)據(jù)庫設(shè)置好自增長主鍵后,可通過JDBC的getGeneratedKeys方法獲取。但像Oralce等不支持auto-generated key field的數(shù)據(jù)庫就不能用這種方法獲取主鍵了
flushCache
:取值范圍true(默認(rèn)值)|false,設(shè)置執(zhí)行該操作后是否會清空二級緩存和本地緩存
timeout
:默認(rèn)為unset(依賴jdbc驅(qū)動器的設(shè)置),設(shè)置執(zhí)行該操作的最大時限,超時將拋異常
databaseId
:取值范圍oracle|mysql等,表示數(shù)據(jù)庫廠家,元素內(nèi)部可通過`<if test="_databaseId = 'oracle'">`來為特定數(shù)據(jù)庫指定不同的sql語句
對于不支持自動生成類型的數(shù)據(jù)庫或可能不支持自動生成主鍵JDBC驅(qū)動來說,MyBatis有另外一種方法來生成主鍵。
這里有一個簡單的示例,它可以生成一個隨機ID(最好不要這么做,但這里展示了MyBatis處理問題的靈活性及其所關(guān)心的廣度):
<insert id="saveFood" > <!-- selectKey 在Mybatis中是為了解決Insert數(shù)據(jù)時不支持主鍵自動生成的問題,他可以很隨意的設(shè)置生成主鍵的方式。 SelectKey需要注意order屬性,像Mysql一類支持自動增長類型的數(shù)據(jù)庫中, order需要設(shè)置為after才會取到正確的值。像Oracle這樣取序列的情況,需要設(shè)置為before,否則會報錯。 keyProperty:selectKey 語句結(jié)果應(yīng)該被設(shè)置的目標(biāo)屬性。 order:可設(shè)置為 BEFORE 或 AFTER,如果設(shè)置為 BEFORE,那么它會首先選擇主鍵,設(shè)置 keyProperty 然后執(zhí)行插入語句。 如果設(shè)置為 AFTER,那么先執(zhí)行插入語句,然后是 執(zhí)行selectKey元素 statementType:和前面的相 同,MyBatis 支持 STATEMENT ,PREPARED 和CALLABLE 語句的映射類型, 分別代表 PreparedStatement 和CallableStatement 類型。 注意:selectKey操作會將操作查詢結(jié)果賦值到insert元素的parameterType的入?yún)嵗聦?yīng)的屬性中。并提供給insert語句使用 --> <selectKey keyProperty="foodId" order="BEFORE" resultType="int" statementType="STATEMENT"> select FOOD_SEC.Nextval from dual </selectKey> insert into food values(#{foodId},#{foodName},#{price}) </insert>
在上面的示例中,selectKey元素將會首先運行,food的id會被設(shè)置,然后插入語句會被調(diào)用,這給了你一個和數(shù)據(jù)庫中來處理自動生成的主鍵類似的行為,避免了使Java代碼變得復(fù)雜
這個元素可以被用來定義可重用的SQL代碼段,可以包含在其他語句中,它可以被靜態(tài)地(在加載參數(shù))參數(shù)化,不同的屬性值太高包含的實例變化。
比如:
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
這個SQL片段可以被包含在其他語句中,例如:
<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>
屬性值可以用于包含的refid屬性或者包含的字句里面的屬性值。
resultMap 元素時MyBatis中最重要最強大的元素。它就是讓你遠(yuǎn)離90%的需要從結(jié)果集中取出數(shù)據(jù)的JDBC代碼的那個東西,而且在一些情形下允許你做一些JDBC不支持的事情。事實上,編寫相似于對復(fù)雜語句聯(lián)合映射這些等同的代碼,也許可以跨過上千行的代碼。ResultMap的設(shè)計就是簡單語句不需要明確的結(jié)果映射,而很多復(fù)雜語句確實需要描述它們的關(guān)系。
<!-- resultMap 基本作用:建立SQL查詢結(jié)果字段與實體屬性的映射關(guān)系 屬性 id屬性 ,resultMap標(biāo)簽的標(biāo)識。 type屬性 ,返回值的全限定類名,或類型別名。 autoMapping 屬性 ,值范圍true(默認(rèn)值)|false,設(shè)置是否啟動自動映射功能, 自動映射功能就是自動查找與字段名小寫同名的屬性名,并調(diào)用setter方法。而設(shè)置為false后, 則需要在resultMap內(nèi)明確注明映射關(guān)系才會調(diào)用對應(yīng)的setter方法。 子元素: id元素 ,用于設(shè)置主鍵字段與領(lǐng)域模型屬性的映射關(guān)系 result元素 ,用于設(shè)置普通字段與領(lǐng)域模型屬性的映射關(guān)系 property 需要映射到JavaBean 的屬性名稱。 column 數(shù)據(jù)表的列名或者標(biāo)簽別名。 javaType 一個完整的類名,或者是一個類型別名。如果你匹配的是一個JavaBean, 那MyBatis 通常會自行檢測到。然后,如果你是要映射到一個HashMap, 那你需要指定javaType 要達(dá)到的目的。 jdbcType 數(shù)據(jù)表支持的類型列表。這個屬性只在insert,update 或delete 的時候針對允許空的列有用。 JDBC 需要這項,但MyBatis 不需要。如果你是直接針對JDBC 編碼,且有允許空的列,而你要指定這項。 typeHandler 使用這個屬性可以覆寫類型處理器。這項值可以是一個完整的類名,也可以是一個類型別名。 association聯(lián)合 聯(lián)合元素用來處理“一對一”的關(guān)系。需要指定映射的Java實體類的屬性,屬性的javaType(通常MyBatis 自己會識別)。 對應(yīng)的數(shù)據(jù)庫表的列名稱。如果想覆寫的話返回結(jié)果的值,需要指定typeHandler。 不同情況需要告訴MyBatis 如何加載一個聯(lián)合。MyBatis 可以用兩種方式加載: select: 執(zhí)行一個其它映射的SQL 語句返回一個Java實體類型。較靈活; resultsMap: 使用一個嵌套的結(jié)果映射來處理通過join查詢結(jié)果集,映射成Java實體類型。 --> <resultMap type="grade" id="gradeMap" autoMapping="true" > <!-- 因為 autoMapping="false"(默認(rèn)是true) 所以要明確注明映射關(guān)系 如果為true則會自動映射 不需要寫下面這行代碼 <result column="gid" property="gid"/> 還有下面這種方法 需要gid為主鍵的情況下使用 列和屬性的關(guān)系 主鍵使用id 非主鍵使用result <id column="gid" property="gid"/> --> <!-- 將查詢的結(jié)果gname賦給gname1 --> <id column="gid" property="gid"/> <result column="gname" property="gname"/> </resultMap>
到此,關(guān)于“基于Mybatis的配置文件的原理”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。