詳解mybatis-config.xml文件

<?xml version="1.0" encoding=UTF-8">
<configuration><!--配置-->
    <properties/><!--屬性-->
    <settings/><!--設置-->
    <typeAliases><!--類型命名-->
    <typeHandler><!--類型處理器-->
    <objectFactory><!--對象工廠-->
    <plugins><!--插件-->
    <!-- 配置全局屬性 -->
    <environments><!--配置環境-->
        <environment><!--環境變量-->
            <transactionManager/><!--事務管理器-->
            <dataSource/><!--數據源-->
        </environment>
    </environments>
    <databaseIdProvider/><!--數據庫廠商標識-->
    <mappers/><!--映射器-->
</configuration>

properties元素

properties是一個配置屬性的元素,讓我們能在配置文件的上下文中使用它。
MyBatis提供3中配置方式:

  • property子元素
  • properties配置文件
  • 程序參數傳遞

property子元素

<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf8" />
<property name="username" value="root" />
<property name="password" value="root" />

這樣我們就可以在上下文中使用已經配置好的屬性值了。我們配置數據庫時就可以按照以下方式配置

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

properties
properties還可以加載配置文件,如jdbc.properties,並以比較簡潔的方式進行數據庫的配置

<properties resource="jdbc.properties" />
<dataSource type="POOLED">
    <property name="driver" value="${jdbc.Driver}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.userName}" />
    <property name="password" value="${jdbc.passWd}" />
</dataSource>

jdbc.properties配置文件內容如下:

jdbc.Driver=com.mysql.jdbc.Driver
jdbc.userName=root
jdbc.passWd=root
jdbc.url=jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf8

由於以上兩種爲常用的配置,所以只分析它們。
優先級
MyBatis支持的3中配置方式可能同時出現,並且屬性還會重複配置,其實這三種方式是存在優先級的,MyBatis將按照下面的順序來進行加載

  1. 在properties元素體內指定的屬性首先被讀取
  2. 根據properties元素中的resource屬性讀取類路徑下的屬性文件;或者根據url屬性指定的路徑讀取屬性文件,並覆蓋已讀取的同名屬性
  3. 讀取作爲方法參數傳遞的屬性,並覆蓋已讀取的同名屬性

因此,通過方法參數傳遞的屬性具有最高優先級,resource/url屬性中指定的配置文件次之,最低優先級是properties屬性中指定的屬性
推薦使用properties文件的形式

Settings

settings在Mybatis中是最複雜的配置,同時也是最爲重要的配置內容之一,它會改變MyBatis運行時的行爲。即使不配置settings,MyBatis也可以正常工作。

typeAliases

別名是一個指點的名稱,因爲我們遇到的類全限定名過長,所以我們希望用一個簡短的名稱去指代它,這個名稱可以在MyBatis上下文重視會用。別名可以分爲系統定義別名自定義別名兩類。在Mybatis中別名是不區分大小寫的。一個typeAliases的實例是在解析配置文件時生成的,然後長期保存在Configuration對象中,當我們使用它時,再把它拿出來,這樣就沒有必要運行的時候再次生成它的實例了。
系統定義別名
MyBatis系統定義了一些經常使用的類型的別名,如數值,字符串,日期和集合等,我們可以在MyBatis中直接使用它們,在使用時不要重複定義把它們給覆蓋了
其實我們可以在 org.apache.ibatis.type.TypeAliasRegistry這個類中查看別名信息。

 registerAlias("string", String.class);
 registerAlias("byte", Byte.class);
 registerAlias("long", Long.class);
 registerAlias("short", Short.class);
 registerAlias("int", Integer.class);
 registerAlias("integer", Integer.class);
 registerAlias("double", Double.class);
 registerAlias("float", Float.class);
 registerAlias("boolean", Boolean.class);
 ...

自定義別名
因爲不同的應用有不同的需要,系統所定義的別名往往不夠用,所以MyBatis允許自定義的別名。我們可以用typeAliases配置別名。也可以使用@Alias方法註冊別名。如

<typeAliases>
        <typeAlias type="com.wojiushiwo.mybatis_demo.User" alias="user" />
</typeAliases>

這樣就在MyBatis的上下文中使用”user”來代替其全路徑,減少配置的複雜度

如果POJO類較多的話,以上面的方式配置也稍顯麻煩。我們可以通過掃描包的方式。如下

<typeAliases>
        <package name="com.wojiushiwo.mybatis_demo" />
</typeAliases>

在實體類上添加上註解,定義別名

@Alias(value="user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;

這樣,MyBatis就能夠掃描到POJO類,並且指定其別名
如果配置了包掃描,而POJO類沒有註解@alias,它也會被裝載,只是它會把類的第一個字母變爲小寫,然後把改變後的類名作爲MyBatis的別名。
定義別名時要特別注意,別名不要重複

typeHandler

Mybatis在預處理語句中設置一個參數時。或者從結果集中取出一個值時,都會使用到typeHandler。typeHandler允許根據項目的需要自定義設置Java傳遞到數據庫的參數中,或者從數據庫讀出數據,這些都可以在自定義的typeHandler中處理。

typeHandler也分爲系統定義和用戶自定義兩種。

typeHandler常用的配置爲Java類型(javaType)、JDBC類型(jdbcType).typeHandler的作用就是將參數從JavaType轉化爲jdbcType;或者從數據庫取出結果時把jdbcType轉換爲javaType

系統定義的typeHandler,可以通過org.apache.ibatis.type.TypeHandlerRegistry查看,如下

 ...
 register(Boolean.class, new BooleanTypeHandler());
 register(boolean.class, new BooleanTypeHandler());
 register(JdbcType.BOOLEAN, new BooleanTypeHandler());
 register(JdbcType.BIT, new BooleanTypeHandler());

 register(Byte.class, new ByteTypeHandler());
 register(byte.class, new ByteTypeHandler());
 register(JdbcType.TINYINT, new ByteTypeHandler());
 ...

自定義TypeHandler
當我們需要特殊的處理Java的那些類型和對應處理數據庫的那些類型時,系統定義的typeHandler已經應付不了的時候,我們考慮自定義typeHandler。

自定義typeHandler需要實現TypeHandler接口

@MappedTypes(value = { String.class })
@MappedJdbcTypes(value = { JdbcType.VARCHAR })
public class MyStringTypeHandler implements TypeHandler<String> {
    private Logger log = Logger.getLogger(MyStringTypeHandler.class);

    @Override
    public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        log.info("使用我的typeHandler");
        ps.setString(i, parameter);

    }

    @Override
    public String getResult(ResultSet rs, String columnName) throws SQLException {
        log.info("使用我的typeHandler,ResultSet列名獲取字符串");
        return rs.getString(columnName);
    }

    @Override
    public String getResult(ResultSet rs, int columnIndex) throws SQLException {
        log.info("使用我的typeHandler,ResultSet下標獲取字符串");
        return rs.getString(columnIndex);
    }

    @Override
    public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
        log.info("使用我的typeHandler,CallableStatement下標獲取字符串");
        return cs.getString(columnIndex);
    }

}

重寫TypeHandler的方法,方法大概有:爲預編譯語句設置參數、根據列名從結果集中獲取數據、根據列索引從結構集中獲取數據、從存儲過程中獲取數據

自定義typeHandler裏用註解配置JdbcType和JavaType,這兩個註解是:

  • @MappedTypes定義的是JavaType類型,可以指定哪些Java類型被攔截
  • @MappedJdbcTypes定義的是JdbcType類型,它需要滿足枚舉類org.apache.ibatis.type.JdbcType所列的枚舉類型

    自定義typeHandler在mybatis-config.xml中的使用:

<typeHandlers>
        <typeHandler javaType="String" jdbcType="VARCHAR"
            handler="com.example.demo.handler.MyStringTypeHandler" />
</typeHandlers>
<!--也可以使用包掃描的方式-->
<!--<typeHandlers>
    <package name="com.example.demo.handler.MyStringTypeHandler"/>
</typeHandlers>
-->

常見的使用自定義typeHandler的方式:

<resultMap type="com.example.demo.entity.User" id="User">
    <!-- 方式一 使用自定義的typeHandler -->
    <!-- <result column="name" property="name" javaType="string" jdbcType="VARCHAR" 
        /> -->
    <!-- 方式二使用自定義的typeHandler -->
    <result column="name" property="name"
        typeHandler="com.example.demo.handler.MyStringTypeHandler" />
    </resultMap>

枚舉類型處理器
先定義一個枚舉類:

public enum Sex {
    MALE(1, "男"), FEMALE(2, "女");
    private int id;
    private String name;

    private Sex(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static Sex getSex(int id) {
        if (id == 1) {
            return Sex.MALE;
        } else if (id == 2) {
            return Sex.FEMALE;
        }
        return null;

    }
}

EnumTypeHandler、EnumOrdinalTypeHandler均可作爲枚舉類型處理器,但兩者存在區別:

EnumOrdinalTypeHandler獲取的是枚舉定義的下標,如1,2;EnumTypeHandler獲取的是枚舉定義的name,如男,女

截取一部分源碼說明問題:

EnumTypeHandler
 @Override
  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
    if (jdbcType == null) {
      ps.setString(i, parameter.name());
    } else {
      ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589
    }
  }
EnumOrdinalTypeHandler
 @Override
  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
    ps.setInt(i, parameter.ordinal());
  }

使用方式:

<typeHandlers>
        <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
            javaType="com.example.demo.entity.Sex" />
    </typeHandlers>
<!--user類中定義了該Sex枚舉屬性-->
<resultMap type="com.example.demo.entity.User" id="User">
        ...
        <result column="sex" property="sex"
            typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />
        ...
    </resultMap>

ObjectFactory

當MyBatis從數據庫取得數據返回的時候,都會使用ObjectFactory去構建POJO;在MyBatis中可以定製自己的對象工廠。一般來說我麼們使用默認的ObjectFactory(org.apache.ibatis.reflection.factory.DefaultObjectFactory)即可。當然我們也可以自己自定義。

public class MyObjectFactory extends DefaultObjectFactory {
    private static final long serialVersionUID = 6016076182957642243L;
    private Logger log = Logger.getLogger(MyObjectFactory.class);

    @Override
    public <T> T create(Class<T> type) {
        log.info("使用定製對象工廠 創建單個對象");
        return super.create(type);
    }

    @Override
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        log.info("使用定製對象工廠 創建列表對象");
        return super.create(type, constructorArgTypes, constructorArgs);
    }

    @Override
    public void setProperties(Properties properties) {
        log.info("定製屬性:" + properties);
        super.setProperties(properties);
    }


    @Override
    public <T> boolean isCollection(Class<T> type) {
        return super.isCollection(type);
    }

}

我們可以通過實現ObjectFactory接口來構建ObjectFactory。但是由於DefaultObjectFactory已經實現了ObjectFactory的接口,我們可以通過繼承DefaultObjectFactory來簡化編程。一般我們不需要使用自己配置的ObjectFactory,使用系統默認即可

代碼中setProperties方法可以使我們如何去處理設置進去的屬性,而create方法可以分別處理單個對象和列表對象。

在mybatis-config.xml中使用
<objectFactory type="com.example.demo.factory.MyObjectFactory">
        <property name="name" value="MyObjectFactory" />
</objectFactory>

environments

<!-- 配置全局屬性 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.Driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.userName}" />
                <property name="password" value="${jdbc.passWd}" />
            </dataSource>
        </environment>
    </environments>

配置環境可以註冊多個數據源,每個數據源可以分爲兩大部分:一個是數據源的配置,一個是數據庫事務的配置。

  • environments中的屬性default,表明在缺省的情況下,我們將啓動哪個數據源配置
  • environment元素是配置一個數據源的開始;屬性id是設置這個數據源的標識,以便MyBatis上下文使用它
  • transactionManager配置的是數據庫事務,其中type屬性有3種配置方式:
    JDBC:採用JDBC方式管理事務,在獨立編碼中經常使用
    MANAGED:採用容器方式管理事務,在JNDI數據源中常用
    自定義,由使用者自定義數據庫事務管理辦法,適用於特殊應用

  • property元素則可以配置數據源的各類屬性,autoCommit=false則表示數據源不自動提交

  • dataSource:配置數據源連接的信息,type屬性是提供我們對數據庫連接方式的配置:
    UNPOOLED 非連接池數據庫
    POOLED 連接池數據庫
    JNDI JNDI數據源
    自定義數據源

數據源

  • UNPOOLED 非連接池 使用 org.apache.ibatis.datasource.unpooled.UnpooledDataSource實現
  • POOLED 連接池 使用org.apache.ibatis.datasource.pooled.PooledDataSource實現
  • JNDI 使用org.apache.ibatis.datasource.jndi.JndiDataSourceFactory來獲取數據源

如果我們需要自定義數據源,必須實現org.apache.ibatis.datasource.DataSourceFactory接口

Mapper

引入mapper的方式:

<mappers>   
        <!--使用文件路徑引入-->
        <mapper resource="com.wojiushiwo/UserMapper.xml"/>
        <mapper resource="com.wojiushiwo/ArticleMapper.xml"/>
    </mappers>
<mappers>
        <!--使用類註冊引入-->
        <mapper class="com.wojiushiwo.mybatis_demo.UserMapper"/>
</<mappers>
<mappers>
        <!--使用包名引入-->
        <package name="com.wojiushiwo.mybatis_demo"/>
</<mappers>

參考文獻:
深入淺出MyBatis技術原理與實戰

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章