Mybatis基礎(chǔ)知識(shí)1-XML配置

參考w3c 教程

1.概述

  • MyBatis 是支持定制化SQL、存儲(chǔ)過程以及高級(jí)映射的優(yōu)秀的持久層框架摧阅。MyBatis 避免了幾乎所有的 JDBC 代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集香璃。MyBatis 可以對(duì)配置和原生Map使用簡(jiǎn)單的 XML 或注解虱咧,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對(duì)象)映射成數(shù)據(jù)庫中的記錄叉庐。

  • 安裝
    使用 Maven 來構(gòu)建項(xiàng)目,則需將下面的 dependency 代碼置于 pom.xml 文件中:

<dependency>  
    <groupId>org.mybatis</groupId>  
    <artifactId>mybatis</artifactId>  
    <version>x.x.x</version>
</dependency>
  • 功能架構(gòu)
    1)API接口層:提供給外部使用的接口API儿惫,開發(fā)人員通過這些本地API來操縱數(shù)據(jù)庫。接口層一接收到調(diào)用請(qǐng)求就會(huì)調(diào)用數(shù)據(jù)處理層來完成具體的數(shù)據(jù)處理伸但。
    2)數(shù)據(jù)處理層:負(fù)責(zé)具體的SQL查找肾请、SQL解析、SQL執(zhí)行和執(zhí)行結(jié)果映射處理等更胖。它主要的目的是根據(jù)調(diào)用的請(qǐng)求完成一次數(shù)據(jù)庫操作铛铁。
    3)基礎(chǔ)支撐層:負(fù)責(zé)最基礎(chǔ)的功能支撐,包括連接管理函喉、事務(wù)管理避归、配置加載和緩存處理,這些都是共用的東西管呵,將他們抽取出來作為最基礎(chǔ)的組件梳毙。為上層的數(shù)據(jù)處理層提供最基礎(chǔ)的支撐。

  • 優(yōu)點(diǎn)
    1)簡(jiǎn)單易學(xué):本身就很小且簡(jiǎn)單捐下。沒有任何第三方依賴账锹,最簡(jiǎn)單安裝只要兩個(gè)jar文件+配置幾個(gè)sql映射文件易于學(xué)習(xí)萌业,易于使用,通過文檔和源代碼奸柬,可以比較完全的掌握它的設(shè)計(jì)思路和實(shí)現(xiàn)生年。
    2)靈活:mybatis不會(huì)對(duì)應(yīng)用程序或者數(shù)據(jù)庫的現(xiàn)有設(shè)計(jì)強(qiáng)加任何影響。 sql寫在xml里廓奕,便于統(tǒng)一管理和優(yōu)化抱婉。通過sql基本上可以實(shí)現(xiàn)我們不使用數(shù)據(jù)訪問框架可以實(shí)現(xiàn)的所有功能,或許更多桌粉。
    3)解除sql與程序代碼的耦合:通過提供DAL層蒸绩,將業(yè)務(wù)邏輯和數(shù)據(jù)訪問邏輯分離,使系統(tǒng)的設(shè)計(jì)更清晰铃肯,更易維護(hù)患亿,更易單元測(cè)試。sql和代碼的分離押逼,提高了可維護(hù)性步藕。
    4)提供映射標(biāo)簽,支持對(duì)象與數(shù)據(jù)庫的orm字段關(guān)系映射
    5)提供對(duì)象關(guān)系映射標(biāo)簽挑格,支持對(duì)象關(guān)系組建維護(hù)
    6)提供xml標(biāo)簽咙冗,支持編寫動(dòng)態(tài)sql。

  • 缺點(diǎn)
    1)編寫SQL語句時(shí)工作量很大恕齐,尤其是字段多乞娄、關(guān)聯(lián)表多時(shí),更是如此显歧。
    2)SQL語句依賴于數(shù)據(jù)庫仪或,導(dǎo)致數(shù)據(jù)庫移植性差,不能更換數(shù)據(jù)庫士骤。
    3)框架還是比較簡(jiǎn)陋范删,功能尚有缺失,雖然簡(jiǎn)化了數(shù)據(jù)綁定代碼拷肌,但是整個(gè)底層數(shù)據(jù)庫查詢實(shí)際還是要自己寫的到旦,工作量也比較大,而且不太容易適應(yīng)快速數(shù)據(jù)庫修改巨缘。
    4)二級(jí)緩存機(jī)制不佳

2.XML配置

  • 包含設(shè)置信息(settings)和屬性信息(properties)

2.1 properties

  • 這些屬性都是可外部配置且可動(dòng)態(tài)替換的添忘,既可以在典型的 Java 屬性文件中配置,亦可通過 properties 元素的子元素來傳遞若锁。例如:
<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</properties>

其中的屬性就可以在整個(gè)配置文件中使用來替換需要?jiǎng)討B(tài)配置的屬性值搁骑。比如:

<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

這個(gè)例子中的 username 和 password 將會(huì)由 properties 元素中設(shè)置的相應(yīng)值來替換。 driver 和 url 屬性將會(huì)由 config.properties 文件中對(duì)應(yīng)的值來替換。這樣就為配置提供了諸多靈活選擇仲器。
屬性也可以被傳遞到 SqlSessionBuilder.build()方法中煤率。例如:

    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props);

    // ... or ...

    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, props);

如果屬性在不只一個(gè)地方進(jìn)行了配置,那么 MyBatis 將按照下面的順序來加載:
1)在 properties 元素體內(nèi)指定的屬性首先被讀取乏冀。
2)然后根據(jù) properties 元素中的 resource 屬性讀取類路徑下屬性文件或根據(jù) url 屬性指定的路徑讀取屬性文件蝶糯,并覆蓋已讀取的同名屬性。
3)最后讀取作為方法參數(shù)傳遞的屬性辆沦,并覆蓋已讀取的同名屬性昼捍。
因此,通過方法參數(shù)傳遞的屬性具有最高優(yōu)先級(jí)众辨,resource/url 屬性中指定的配置文件次之端三,最低優(yōu)先級(jí)的是 properties 屬性中指定的屬性

2.2 settings

  • 會(huì)改變 MyBatis 的運(yùn)行時(shí)行為





<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

2.3 typeAliases

  • 類型別名是為 Java 類型設(shè)置一個(gè)短的名字。它只和 XML 配置有關(guān)鹃彻,存在的意義僅在于用來減少類完全限定名的冗余。例如:
<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

當(dāng)這樣配置時(shí)妻献,Blog可以用在任何使用domain.blog.Blog的地方蛛株。
也可以指定一個(gè)包名,MyBatis 會(huì)在包名下面搜索需要的 Java Bean育拨,比如:

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

每一個(gè)在包 domain.blog 中的 Java Bean谨履,在沒有注解的情況下,會(huì)使用 Bean 的首字母小寫的非限定類名來作為它的別名熬丧。 比如 domain.blog.Author 的別名為 author笋粟;若有注解,則別名為其注解值析蝴『Σ叮看下面的例子:

    @Alias("author")
    public class Author {
        ...
    }

已經(jīng)為許多常見的 Java 類型內(nèi)建了相應(yīng)的類型別名。它們都是大小寫不敏感的闷畸,需要注意的是由基本類型名稱重復(fù)導(dǎo)致的特殊處理尝盼。



2.4 typeHandlers

  • 無論是 MyBatis 在預(yù)處理語句(PreparedStatement)中設(shè)置一個(gè)參數(shù)時(shí),還是從結(jié)果集中取出一個(gè)值時(shí)佑菩, 都會(huì)用類型處理器將獲取的值以合適的方式轉(zhuǎn)換成 Java 類型盾沫。下表描述了一些默認(rèn)的類型處理器。



  • 你可以重寫類型處理器或創(chuàng)建你自己的類型處理器來處理不支持的或非標(biāo)準(zhǔn)的類型殿漠。 具體做法為:實(shí)現(xiàn) org.apache.ibatis.type.TypeHandler 接口赴精, 或繼承一個(gè)很便利的類 org.apache.ibatis.type.BaseTypeHandler, 然后可以選擇性地將它映射到一個(gè) JDBC 類型绞幌。
    // ExampleTypeHandler.java
    @MappedJdbcTypes(JdbcType.VARCHAR)
    public class ExampleTypeHandler extends BaseTypeHandler {

      @Override
      public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
      }

      @Override
      public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getString(columnName);
      }

      @Override
      public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getString(columnIndex);
      }

      @Override
      public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
      }
    }
<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

使用這個(gè)的類型處理器將會(huì)覆蓋已經(jīng)存在的處理 Java 的 String 類型屬性和 VARCHAR 參數(shù)及結(jié)果的類型處理器蕾哟。 要注意 MyBatis 不會(huì)窺探數(shù)據(jù)庫元信息來決定使用哪種類型,所以你必須在參數(shù)和結(jié)果映射中指明那是 VARCHAR 類型的字段, 以使其能夠綁定到正確的類型處理器上渐苏。 這是因?yàn)椋篗yBatis 直到語句被執(zhí)行才清楚數(shù)據(jù)類型掀潮。

通過類型處理器的泛型,MyBatis 可以得知該類型處理器處理的 Java 類型琼富,不過這種行為可以通過兩種方法改變:
1)在類型處理器的配置元素(typeHandler element)上增加一個(gè) javaType 屬性(比如:javaType="String")仪吧;
2)在類型處理器的類上(TypeHandler class)增加一個(gè) @MappedTypes 注解來指定與其關(guān)聯(lián)的 Java 類型列表。 如果在 javaType 屬性中也同時(shí)指定鞠眉,則注解方式將被忽略薯鼠。

可以通過兩種方式來指定被關(guān)聯(lián)的 JDBC 類型:
1)在類型處理器的配置元素上增加一個(gè) javaType 屬性(比如:javaType="VARCHAR");
2)在類型處理器的類上(TypeHandler class)增加一個(gè) @MappedJdbcTypes 注解來指定與其關(guān)聯(lián)的 JDBC 類型列表械蹋。 如果在 javaType 屬性中也同時(shí)指定出皇,則注解方式將被忽略。
最后哗戈,可以讓 MyBatis 為你查找類型處理器:

<!-- mybatis-config.xml -->
<typeHandlers>
  <package name="org.mybatis.example"/>
</typeHandlers>

注意在使用自動(dòng)檢索(autodiscovery)功能的時(shí)候郊艘,只能通過注解方式來指定 JDBC 的類型。
你能創(chuàng)建一個(gè)泛型類型處理器唯咬,它可以處理多于一個(gè)類纱注。為達(dá)到此目的, 需要增加一個(gè)接收該類作為參數(shù)的構(gòu)造器胆胰,這樣在構(gòu)造一個(gè)類型處理器的時(shí)候 MyBatis 就會(huì)傳入一個(gè)具體的類狞贱。

    //GenericTypeHandler.java
    public class GenericTypeHandler extends BaseTypeHandler {

      private Class type;

      public GenericTypeHandler(Class type) {
        if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
        this.type = type;
      }
      ...

EnumTypeHandler 和 EnumOrdinalTypeHandler 都是泛型類型處理器(generic TypeHandlers)

2.5 處理枚舉類型

  • 若想映射枚舉類型 Enum,則需要從 EnumTypeHandler 或者 EnumOrdinalTypeHandler 中選一個(gè)來使用蜀涨。
    比如說我們想存儲(chǔ)取近似值時(shí)用到的舍入模式瞎嬉。默認(rèn)情況下,MyBatis 會(huì)利用 EnumTypeHandler 來把 Enum 值轉(zhuǎn)換成對(duì)應(yīng)的名字厚柳。
    注意 EnumTypeHandler 在某種意義上來說是比較特別的氧枣,其他的處理器只針對(duì)某個(gè)特定的類,而它不同草娜,它會(huì)處理任意繼承了 Enum 的類挑胸。
    不過,我們可能不想存儲(chǔ)名字宰闰,相反我們的 DBA 會(huì)堅(jiān)持使用整形值代碼茬贵。那也一樣輕而易舉: 在配置文件中把 EnumOrdinalTypeHandler 加到 typeHandlers 中即可, 這樣每個(gè) RoundingMode 將通過他們的序數(shù)值來映射成對(duì)應(yīng)的整形移袍。
<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>
</typeHandlers>
  • 但是怎樣能將同樣的 Enum 既映射成字符串又映射成整形呢解藻?
    自動(dòng)映射器(auto-mapper)會(huì)自動(dòng)地選用 EnumOrdinalTypeHandler 來處理, 所以如果我們想用普通的 EnumTypeHandler葡盗,就非要為那些 SQL 語句顯式地設(shè)置要用到的類型處理器不可螟左。
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
    <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="funkyNumber" property="funkyNumber"/>
        <result column="roundingMode" property="roundingMode"/>
    </resultMap>

    <select id="getUser" resultMap="usermap">
        select * from users
    </select>
    <insert id="insert">
        insert into users (id, name, funkyNumber, roundingMode) values (
            #{id}, #{name}, #{funkyNumber}, #{roundingMode}
        )
    </insert>

    <resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="funkyNumber" property="funkyNumber"/>
        <result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
    </resultMap>
    <select id="getUser2" resultMap="usermap2">
        select * from users2
    </select>
    <insert id="insert2">
        insert into users2 (id, name, funkyNumber, roundingMode) values (
            #{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
        )
    </insert>

</mapper>

注意啡浊,這里的 select 語句強(qiáng)制使用 resultMap 來代替 resultType。

2.6 對(duì)象工廠(objectFactory)

  • MyBatis 每次創(chuàng)建結(jié)果對(duì)象的新實(shí)例時(shí)胶背,它都會(huì)使用一個(gè)對(duì)象工廠(ObjectFactory)實(shí)例來完成巷嚣。 默認(rèn)的對(duì)象工廠需要做的僅僅是實(shí)例化目標(biāo)類,要么通過默認(rèn)構(gòu)造方法钳吟,要么在參數(shù)映射存在的時(shí)候通過參數(shù)構(gòu)造方法來實(shí)例化廷粒。 如果想覆蓋對(duì)象工廠的默認(rèn)行為,則可以通過創(chuàng)建自己的對(duì)象工廠來實(shí)現(xiàn)红且。比如:
    // ExampleObjectFactory.java
    public class ExampleObjectFactory extends DefaultObjectFactory {
      public Object create(Class type) {
        return super.create(type);
      }
      public Object create(Class type, List constructorArgTypes, List constructorArgs) {
        return super.create(type, constructorArgTypes, constructorArgs);
      }
      public void setProperties(Properties properties) {
        super.setProperties(properties);
      }
      public  boolean isCollection(Class type) {
        return Collection.class.isAssignableFrom(type);
      }}
<!-- mybatis-config.xml -->
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
  <property name="someProperty" value="100"/>
</objectFactory>

ObjectFactory 接口很簡(jiǎn)單坝茎,它包含兩個(gè)創(chuàng)建用的方法,一個(gè)是處理默認(rèn)構(gòu)造方法的暇番,另外一個(gè)是處理帶參數(shù)的構(gòu)造方法的嗤放。 最后,setProperties 方法可以被用來配置 ObjectFactory壁酬,在初始化你的 ObjectFactory 實(shí)例后次酌, objectFactory 元素體中定義的屬性會(huì)被傳遞給 setProperties 方法。

2.7 插件(plugins)

  • MyBatis 允許你在已映射語句執(zhí)行過程中的某一點(diǎn)進(jìn)行攔截調(diào)用舆乔。默認(rèn)情況下和措,MyBatis 允許使用插件來攔截的方法調(diào)用包括:
    1)Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
    2)ParameterHandler (getParameterObject, setParameters)
    3)ResultSetHandler (handleResultSets, handleOutputParameters)
    4)StatementHandler (prepare, parameterize, batch, update, query)
    這些類中方法的細(xì)節(jié)可以通過查看每個(gè)方法的簽名來發(fā)現(xiàn),或者直接查看 MyBatis 的發(fā)行包中的源代碼蜕煌。 假設(shè)你想做的不僅僅是監(jiān)控方法的調(diào)用,那么你應(yīng)該很好的了解正在重寫的方法的行為诬留。 因?yàn)槿绻谠噲D修改或重寫已有方法的行為的時(shí)候斜纪,你很可能在破壞 MyBatis 的核心模塊。 這些都是更低層的類和方法文兑,所以使用插件的時(shí)候要特別當(dāng)心盒刚。

  • 通過 MyBatis 提供的強(qiáng)大機(jī)制,使用插件是非常簡(jiǎn)單的绿贞,只需實(shí)現(xiàn) Interceptor 接口因块,并指定了想要攔截的方法簽名即可。

    // ExamplePlugin.java
    @Intercepts({@Signature(
      type= Executor.class,
      method = "update",
      args = {MappedStatement.class,Object.class})})
    public class ExamplePlugin implements Interceptor {
      public Object intercept(Invocation invocation) throws Throwable {
        return invocation.proceed();
      }
      public Object plugin(Object target) {
        return Plugin.wrap(target, this);
      }
      public void setProperties(Properties properties) {
      }
    }
<!-- mybatis-config.xml -->
<plugins>
  <plugin interceptor="org.mybatis.example.ExamplePlugin">
    <property name="someProperty" value="100"/>
  </plugin>
</plugins> 

上面的插件將會(huì)攔截在 Executor 實(shí)例中所有的 "update" 方法調(diào)用籍铁, 這里的 Executor 是負(fù)責(zé)執(zhí)行低層映射語句的內(nèi)部對(duì)象涡上。

  • NOTE 覆蓋配置類
    除了用插件來修改 MyBatis 核心行為之外,還可以通過完全覆蓋配置類來達(dá)到目的拒名。只需繼承后覆蓋其中的每個(gè)方法吩愧,再把它傳遞到 sqlSessionFactoryBuilder.build(myConfig) 方法即可。再次重申增显,這可能會(huì)嚴(yán)重影響 MyBatis 的行為雁佳,務(wù)請(qǐng)慎之又慎。

2.8 配置環(huán)境(environments)

  • MyBatis 可以配置成適應(yīng)多種環(huán)境,這種機(jī)制有助于將 SQL 映射應(yīng)用于多種數(shù)據(jù)庫之中糖权, 現(xiàn)實(shí)情況下有多種理由需要這么做堵腹。例如,開發(fā)星澳、測(cè)試和生產(chǎn)環(huán)境需要有不同的配置疚顷;或者共享相同 Schema 的多個(gè)生產(chǎn)數(shù)據(jù)庫, 想使用相同的 SQL 映射募判。許多類似的用例荡含。
    不過要記住:盡管可以配置多個(gè)環(huán)境届垫,每個(gè) SqlSessionFactory 實(shí)例只能選擇其一释液。
    所以,如果你想連接兩個(gè)數(shù)據(jù)庫装处,就需要?jiǎng)?chuàng)建兩個(gè) SqlSessionFactory 實(shí)例误债,每個(gè)數(shù)據(jù)庫對(duì)應(yīng)一個(gè)。而如果是三個(gè)數(shù)據(jù)庫妄迁,就需要三個(gè)實(shí)例寝蹈,依此類推,記起來很簡(jiǎn)單:
    每個(gè)數(shù)據(jù)庫對(duì)應(yīng)一個(gè) SqlSessionFactory 實(shí)例

  • 為了指定創(chuàng)建哪種環(huán)境登淘,只要將它作為可選的參數(shù)傳遞給 SqlSessionFactoryBuilder 即可箫老。可以接受環(huán)境配置的兩個(gè)方法簽名是:

    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);
    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);

如果忽略了環(huán)境參數(shù)黔州,那么默認(rèn)環(huán)境將會(huì)被加載耍鬓,如下所示:

    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);

環(huán)境元素定義了如何配置環(huán)境。

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    </dataSource>
  </environment>
</environments>
  • 注意這里的關(guān)鍵點(diǎn):
    1)默認(rèn)的環(huán)境 ID(比如:default="development")流妻。
    2)每個(gè) environment 元素定義的環(huán)境 ID(比如:id="development")牲蜀。
    3)事務(wù)管理器的配置(比如:type="JDBC")。
    4)數(shù)據(jù)源的配置(比如:type="POOLED")绅这。
    默認(rèn)的環(huán)境和環(huán)境 ID 是一目了然的涣达。隨你怎么命名,只要保證默認(rèn)環(huán)境要匹配其中一個(gè)環(huán)境ID证薇。

  • 事務(wù)管理器(transactionManager)
    在 MyBatis 中有兩種類型的事務(wù)管理器(也就是 type="[JDBC|MANAGED]"):
    1)JDBC – 這個(gè)配置就是直接使用了 JDBC 的提交和回滾設(shè)置度苔,它依賴于從數(shù)據(jù)源得到的連接來管理事務(wù)范圍。
    2)MANAGED – 這個(gè)配置幾乎沒做什么棕叫。它從來不提交或回滾一個(gè)連接林螃,而是讓容器來管理事務(wù)的整個(gè)生命周期(比如 JEE 應(yīng)用服務(wù)器的上下文)。 默認(rèn)情況下它會(huì)關(guān)閉連接俺泣,然而一些容器并不希望這樣疗认,因此需要將 closeConnection 屬性設(shè)置為 false 來阻止它默認(rèn)的關(guān)閉行為完残。例如:

<transactionManager type="MANAGED">
  <property name="closeConnection" value="false"/>
</transactionManager>

NOTE : 如果你正在使用 Spring + MyBatis,則沒有必要配置事務(wù)管理器横漏, 因?yàn)?Spring 模塊會(huì)使用自帶的管理器來覆蓋前面的配置谨设。
這兩種事務(wù)管理器類型都不需要任何屬性。它們不過是類型別名缎浇,換句話說扎拣,你可以使用 TransactionFactory 接口的實(shí)現(xiàn)類的完全限定名或類型別名代替它們。

    public interface TransactionFactory {
      void setProperties(Properties props);
      Transaction newTransaction(Connection conn);
      Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
    }

任何在 XML 中配置的屬性在實(shí)例化之后將會(huì)被傳遞給 setProperties() 方法素跺。你也需要?jiǎng)?chuàng)建一個(gè) Transaction 接口的實(shí)現(xiàn)類禀综,這個(gè)接口也很簡(jiǎn)單:

    public interface Transaction {
      Connection getConnection() throws SQLException;
      void commit() throws SQLException;
      void rollback() throws SQLException;
      void close() throws SQLException;
    }

使用這兩個(gè)接口彼城,你可以完全自定義 MyBatis 對(duì)事務(wù)的處理。

  • 數(shù)據(jù)源(dataSource)
    dataSource 元素使用標(biāo)準(zhǔn)的 JDBC 數(shù)據(jù)源接口來配置 JDBC 連接對(duì)象的資源。
    1)許多 MyBatis 的應(yīng)用程序?qū)?huì)按示例中的例子來配置數(shù)據(jù)源型将。然而它并不是必須的覆醇。要知道為了方便使用延遲加載玛痊,數(shù)據(jù)源才是必須的赴恨。

  • 有三種內(nèi)建的數(shù)據(jù)源類型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
    1)UNPOOLED– 這個(gè)數(shù)據(jù)源的實(shí)現(xiàn)只是每次被請(qǐng)求時(shí)打開和關(guān)閉連接。雖然有一點(diǎn)慢箕憾,它對(duì)在及時(shí)可用連接方面沒有性能要求的簡(jiǎn)單應(yīng)用程序是一個(gè)很好的選擇牡借。 不同的數(shù)據(jù)庫在這方面表現(xiàn)也是不一樣的,所以對(duì)某些數(shù)據(jù)庫來說使用連接池并不重要袭异,這個(gè)配置也是理想的钠龙。UNPOOLED 類型的數(shù)據(jù)源僅僅需要配置以下 5 種屬性:
    1-1)driver – 這是 JDBC 驅(qū)動(dòng)的 Java 類的完全限定名(并不是JDBC驅(qū)動(dòng)中可能包含的數(shù)據(jù)源類)。
    1-2)url – 這是數(shù)據(jù)庫的 JDBC URL 地址御铃。
    1-3)username – 登錄數(shù)據(jù)庫的用戶名俊鱼。
    1-4)password – 登錄數(shù)據(jù)庫的密碼。
    1-4)defaultTransactionIsolationLevel – 默認(rèn)的連接事務(wù)隔離級(jí)別畅买。
    作為可選項(xiàng),你也可以傳遞屬性給數(shù)據(jù)庫驅(qū)動(dòng)细睡。要這樣做谷羞,屬性的前綴為"driver.",例如:driver.encoding=UTF8
    這將通過DriverManager.getConnection(url,driverProperties)方法傳遞值為 UTF8 的 encoding 屬性給數(shù)據(jù)庫驅(qū)動(dòng)溜徙。
    2)POOLED– 這種數(shù)據(jù)源的實(shí)現(xiàn)利用"池"的概念將 JDBC 連接對(duì)象組織起來湃缎,避免了創(chuàng)建新的連接實(shí)例時(shí)所必需的初始化和認(rèn)證時(shí)間。 這是一種使得并發(fā) Web 應(yīng)用快速響應(yīng)請(qǐng)求的流行處理方式蠢壹。
    除了上述提到 UNPOOLED 下的屬性外嗓违,會(huì)有更多屬性用來配置 POOLED 的數(shù)據(jù)源:
    2-1)poolMaximumActiveConnections – 在任意時(shí)間可以存在的活動(dòng)(也就是正在使用)連接數(shù)量,默認(rèn)值:10
    2-2)poolMaximumIdleConnections – 任意時(shí)間可能存在的空閑連接數(shù)图贸。
    2-3)poolMaximumCheckoutTime – 在被強(qiáng)制返回之前蹂季,池中連接被檢出(checked out)時(shí)間冕广,默認(rèn)值:20000 毫秒(即 20 秒)
    2-4)poolTimeToWait – 這是一個(gè)底層設(shè)置,如果獲取連接花費(fèi)的相當(dāng)長的時(shí)間偿洁,它會(huì)給連接池打印狀態(tài)日志并重新嘗試獲取一個(gè)連接(避免在誤配置的情況下一直安靜的失斎龊骸),默認(rèn)值:20000 毫秒(即 20 秒)涕滋。
    2-5)poolPingQuery – 發(fā)送到數(shù)據(jù)庫的偵測(cè)查詢睬辐,用來檢驗(yàn)連接是否處在正常工作秩序中并準(zhǔn)備接受請(qǐng)求。默認(rèn)是"NO PING QUERY SET"宾肺,這會(huì)導(dǎo)致多數(shù)數(shù)據(jù)庫驅(qū)動(dòng)失敗時(shí)帶有一個(gè)恰當(dāng)?shù)腻e(cuò)誤消息溯饵。
    2-6)poolPingEnabled – 是否啟用偵測(cè)查詢。若開啟锨用,也必須使用一個(gè)可執(zhí)行的 SQL 語句設(shè)置 poolPingQuery 屬性(最好是一個(gè)非撤峥快的 SQL),默認(rèn)值:false黔酥。
    2-7)poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的使用頻度藻三。這可以被設(shè)置成匹配具體的數(shù)據(jù)庫連接超時(shí)時(shí)間,來避免不必要的偵測(cè)跪者,默認(rèn)值:0(即所有連接每一時(shí)刻都被偵測(cè) — 當(dāng)然僅當(dāng) poolPingEnabled 為 true 時(shí)適用)棵帽。
    3)JNDI– 這個(gè)數(shù)據(jù)源的實(shí)現(xiàn)是為了能在如 EJB 或應(yīng)用服務(wù)器這類容器中使用,容器可以集中或在外部配置數(shù)據(jù)源渣玲,然后放置一個(gè) JNDI 上下文的引用逗概。這種數(shù)據(jù)源配置只需要兩個(gè)屬性:
    3-1)initial_context – 這個(gè)屬性用來在 InitialContext 中尋找上下文(即,initialContext.lookup(initial_context))忘衍。這是個(gè)可選屬性逾苫,如果忽略,那么 data_source 屬性將會(huì)直接從 InitialContext 中尋找枚钓。
    3-2)data_source – 這是引用數(shù)據(jù)源實(shí)例位置的上下文的路徑铅搓。提供了 initial_context 配置時(shí)會(huì)在其返回的上下文中進(jìn)行查找,沒有提供時(shí)則直接在 InitialContext 中查找搀捷。
    和其他數(shù)據(jù)源配置類似星掰,可以通過添加前綴"env."直接把屬性傳遞給初始上下文。比如:env.encoding=UTF8
    這就會(huì)在初始上下文(InitialContext)實(shí)例化時(shí)往它的構(gòu)造方法傳遞值為 UTF8 的 encoding 屬性嫩舟。
    通過需要實(shí)現(xiàn)接口 org.apache.ibatis.datasource.DataSourceFactory 氢烘, 也可使用任何第三方數(shù)據(jù)源,:

    public interface DataSourceFactory {
      void setProperties(Properties props);
      DataSource getDataSource();
    }

org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory 可被用作父類來構(gòu)建新的數(shù)據(jù)源適配器家厌,比如下面這段插入 C3P0 數(shù)據(jù)源所必需的代碼:

    import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
    import com.mchange.v2.c3p0.ComboPooledDataSource;

    public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {

      public C3P0DataSourceFactory() {
        this.dataSource = new ComboPooledDataSource();
      }
    }

為了令其工作播玖,為每個(gè)需要 MyBatis 調(diào)用的 setter 方法中增加一個(gè)屬性。下面是一個(gè)可以連接至 PostgreSQL 數(shù)據(jù)庫的例子:

<dataSource type="org.myproject.C3P0DataSourceFactory">
  <property name="driver" value="org.postgresql.Driver"/>
  <property name="url" value="jdbc:postgresql:mydb"/>
  <property name="username" value="postgres"/>
  <property name="password" value="root"/>
</dataSource>

2.9 databaseIdProvider

MyBatis 可以根據(jù)不同的數(shù)據(jù)庫廠商執(zhí)行不同的語句饭于,這種多廠商的支持是基于映射語句中的 databaseId 屬性蜀踏。 MyBatis 會(huì)加載不帶 databaseId 屬性和帶有匹配當(dāng)前數(shù)據(jù)庫 databaseId 屬性的所有語句维蒙。 如果同時(shí)找到帶有 databaseId 和不帶 databaseId 的相同語句,則后者會(huì)被舍棄脓斩。 為支持多廠商特性只要像下面這樣在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:

<databaseIdProvider type="DB_VENDOR" />

這里的 DB_VENDOR 會(huì)通過 DatabaseMetaData#getDatabaseProductName() 返回的字符串進(jìn)行設(shè)置木西。 由于通常情況下這個(gè)字符串都非常長而且相同產(chǎn)品的不同版本會(huì)返回不同的值,所以最好通過設(shè)置屬性別名來使其變短随静,如下:

<databaseIdProvider type="DB_VENDOR">
  <property name="SQL Server" value="sqlserver"/>
  <property name="DB2" value="db2"/>        
  <property name="Oracle" value="oracle" />
</databaseIdProvider>

在有 properties 時(shí)八千,DB_VENDOR databaseIdProvider 的將被設(shè)置為第一個(gè)能匹配數(shù)據(jù)庫產(chǎn)品名稱的屬性鍵對(duì)應(yīng)的值,如果沒有匹配的屬性將會(huì)設(shè)置為 "null"燎猛。 在這個(gè)例子中恋捆,如果 getDatabaseProductName() 返回"Oracle (DataDirect)",databaseId 將被設(shè)置為"oracle"重绷。

你可以通過實(shí)現(xiàn)接口


    public interface DatabaseIdProvider {
      void setProperties(Properties p);
      String getDatabaseId(DataSource dataSource) throws SQLException;
    }

2.10 映射器(mappers)

既然 MyBatis 的行為已經(jīng)由上述元素配置完了沸停,我們現(xiàn)在就要定義 SQL 映射語句了。但是首先我們需要告訴 MyBatis 到哪里去找到這些語句昭卓。 Java 在自動(dòng)查找這方面沒有提供一個(gè)很好的方法愤钾,所以最佳的方式是告訴 MyBatis 到哪里去找映射文件。你可以使用相對(duì)于類路徑的資源引用候醒, 或完全限定資源定位符(包括 file:/// 的 URL)能颁,或類名和包名等。例如:

<!-- Using classpath relative resources -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- Using url fully qualified paths -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- Using mapper interface classes -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- Register all interfaces in a package as mappers -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

這些配置會(huì)告訴了 MyBatis 去哪里找映射文件倒淫,剩下的細(xì)節(jié)就應(yīng)該是每個(gè) SQL 映射文件了伙菊,也就是接下來我們要討論的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末敌土,一起剝皮案震驚了整個(gè)濱河市镜硕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌返干,老刑警劉巖兴枯,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異矩欠,居然都是意外死亡念恍,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門晚顷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疗疟,你說我怎么就攤上這事该默。” “怎么了策彤?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵栓袖,是天一觀的道長匣摘。 經(jīng)常有香客問我,道長裹刮,這世上最難降的妖魔是什么音榜? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮捧弃,結(jié)果婚禮上赠叼,老公的妹妹穿的比我還像新娘。我一直安慰自己违霞,他們只是感情好嘴办,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著买鸽,像睡著了一般涧郊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上眼五,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天妆艘,我揣著相機(jī)與錄音,去河邊找鬼看幼。 笑死批旺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的桌吃。 我是一名探鬼主播朱沃,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼茅诱!你這毒婦竟也來了逗物?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤瑟俭,失蹤者是張志新(化名)和其女友劉穎翎卓,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摆寄,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡失暴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了微饥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逗扒。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖欠橘,靈堂內(nèi)的尸體忽然破棺而出矩肩,到底是詐尸還是另有隱情,我是刑警寧澤肃续,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布黍檩,位于F島的核電站叉袍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏刽酱。R本人自食惡果不足惜喳逛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望棵里。 院中可真熱鬧润文,春花似錦、人聲如沸衍慎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稳捆。三九已至赠法,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乔夯,已是汗流浹背砖织。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留末荐,地道東北人侧纯。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像甲脏,于是被迫代替她去往敵國和親眶熬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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

  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis 块请? MyBatis 是支持定制化 SQL娜氏、存儲(chǔ)過程以及高級(jí)映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,532評(píng)論 0 4
  • MyBatis 理論篇 [TOC] 什么是MyBatis ?MyBatis是支持普通SQL查詢,存儲(chǔ)過程和高級(jí)映射...
    有_味閱讀 2,911評(píng)論 0 26
  • 812.12.24 10-12點(diǎn),13-18點(diǎn) 總結(jié) 知識(shí)不一定改變你墩新,經(jīng)歷才會(huì)(學(xué)習(xí)就是建立n聯(lián)系)贸弥。多經(jīng)歷,多...
    宇智博閱讀 343評(píng)論 0 0
  • 昨天晚上參加了一個(gè)宣講會(huì)海渊,關(guān)于南方基金的绵疲。聽的有些心馳神往,想要去南方工作了臣疑。雖然心里也明白盔憨,自己跟候選者這個(gè)級(jí)別...
    孔瑞杰閱讀 233評(píng)論 0 0
  • 第一章 九月出生 一九七六年的邱家村,重男輕女思想還很嚴(yán)重讯沈,生個(gè)兒子就是生個(gè)勞動(dòng)力郁岩,生個(gè)女兒...
    中年人甲乙閱讀 335評(píng)論 0 0