mybatis精講(三)--標籤及TypeHandler使用

話引

  • 前兩張咱們分別介紹了Mybatis環境搭建及其組件的生命週期。這些都是咱們Mybatis入門必備技能。有了前兩篇的鋪墊咱們今天就來深刻下Mybatis, 也爲了填下以前埋下的坑。

XML配置標籤

概覽

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration> 
    <!--引入外部配置文件-->
    <properties resource=""/>
    <!--設置-->
    <settings/>
    <!--定義別名-->
    <typeAliases>
        <package name=""/>
    </typeAliases>
    <!--類型處理器-->
    <typeHandlers/>
    <!--對象工廠-->
    <objectFactory/>
    <!--插件-->
    <plugins/>
    <!--定義數據庫信息,默認使用development數據庫構建環境-->
    <environments default="development">
        <environment id="development">
            <!--jdbc事物管理-->
            <transactionManager type="JDBC"/>
            <!--配置數據庫鏈接信息-->
            <dataSource type="POOLED"/>
        </environment>
    </environments>
    <!--數據庫廠商標識-->
    <databaseIdProvider/>
    <mappers/>
</configuration>
  • 上面模板列出了全部xml能夠配置的屬性。這裏plugins是一個讓人啼笑皆非的東西。用的好是利器,用的很差就是埋坑。接下來咱們來看看各個屬性的做用

properties

  • 該標籤的做用就是引入變量。和maven的properties同樣。在這裏定義的變量或者引入的變量,在下面咱們是能夠童工${}使用的。

子標籤property

<properties>
  <property name="zxhtom" value="jdbc:mysql://localhost:3306/mybatis"/>
</properties>

<dataSource type="POOLED">
<property name="driver" value="${zxhtom}"/>
<dataSource>
  • 上述的配置就能夠直接使用zxhtom這個變量。

resource

  • 除了上述方法咱們還能夠經過引入其餘properties文件,就可使用文件裏的配置變量了。

<properties resource="mybatis.properties"/>mysql

程序注入

  • 最後還有一種咱們在構建SqlSessionFactory的時候從新載入咱們的Properties對象就能夠了。另外三者的優先級是從低到高

settings

configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
  • 上面代碼是咱們在XMLConfigBuilder解析settings標籤的代碼。從這段代碼中咱們瞭解到settings子標籤。
參數 功能 可選值 默認值
autoMappingBehavior 指定Mybatis應如何自動映射列到字段上。
NONE : 表示取消自動映射
PARTIAL:只會自動映射沒有定義嵌套結果集映射的結果集
FULL : 自動映射任意複雜的結果集
NONE、PARTIAL、FULL PARTIAL
autoMappingUnknownColumnBehavior 指定識別到位置列或屬性的時間
NONE : 什麼都不作
WARNING:日誌會報警(前提是日誌設置了顯示權限)
FAILING : 拋出異常。
NONE, WARNING, FAILING NONE
cacheEnabled 該配置影響的全部映射器中配置的緩存的全局開關 true|false true
proxyFactory 指定Mybatis建立具備延遲加載能力的對象所用到的代理工具未指定時將自動查找 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING not set
lazyLoadingEnabled 延時加載全局開關
開啓時:級聯對象會延時加載;級聯標籤中能夠經過fetchType來定製覆蓋此選項
true|false false
aggressiveLazyLoading 啓用時:對任意延遲屬性的調用會使帶有延遲加載屬性的對象分層性質完整加載,反之按需加載 true|false true
multipleResultSetsEnabled 是否容許單一語句返回多結果集 true|false true
useColumnLabel 確切的說當映射找不到參數時會使用列標籤(數據庫列名)代替別名去映射 true|false true
useGeneratedKeys 容許 JDBC 支持自動生成主鍵,須要驅動兼容。 若是設置爲 true 則這個設置強制使用自動生成主鍵,儘管一些驅動不能兼容但仍可正常工做(好比 Derby) true|false false
defaultExecutorType 配置默認的執行器。SIMPLE 就是普通的執行器;REUSE 執行器會重用預處理語句(prepared statements); BATCH 執行器將重用語句並執行批量更新 SIMPLE REUSE BATCH SIMPLE
defaultStatementTimeout 設置超時時間,決定驅動等待數據庫響應的秒數 整數 null
defaultFetchSize 設置數據庫resultSet讀取數據方式,默認所有加載進內存,設置該屬性能夠設置一次性讀多少條數據進內存 整數 null
mapUnderscoreToCamelCase 是否開啓自動駝峯命名規則(camel case)映射,即從經典數據庫列名 A_COLUMN 到經典 Java 屬性名 aColumn 的相似映射。 true|false false
safeRowBoundsEnabled -容許在嵌套語句中使用分頁 true|false false
localCacheScope 一級緩存。mybatis默認對同一個sqlsession中數據是共享的。一個sqlsession調用兩次相同查詢實際只會查詢一次。就是由於該屬性爲SESSION , STATEMENT則針對的是每一條sql SESSION|STATEMENT SESSION
jdbcTypeForNull 當沒有爲參數提供特定的jdbc類型時,爲空值則指定JDBC類型。在新增時咱們沒有設置參數,這個時候就會根據此參數天長。加入設置VARCHAR,那麼咱們新增的數據沒傳參數則爲空字符 NULL|VARCHAR|OTHER OTHER
lazyLoadTriggerMethods 指定具體方法延時加載 方法 equals,clone,hashCode,toString
safeResultHandlerEnabled 容許在嵌套語句中使用分頁 true|false true
defaultScriptingLanguage 動態SQL生成的默認語言 org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver
defaultEnumTypeHandler mybatis默認的枚舉處理類
callSettersOnNulls 指定當結果集中值爲null的時候是否調用映射對象的setter(put)方法。
useActualParamName 容許使用他們的編譯後名稱來映射,3.4.2後默認true.在xml中#{0}則報錯。設置爲false,則#{0}表明第一個參數#{n}第n個 true|false true
returnInstanceForEmptyRow 當返回行的全部列都是空時,MyBatis默認返回 null。 當開啓這個設置時,MyBatis會返回一個空實例。 請注意,它也適用於嵌套的結果集 (如集合或關聯)。(新增於 3.4.2) true|false false
logPrefix 指定 MyBatis 增長到日誌名稱的前綴。

別名

  • 別名是mybatis爲咱們項目中類起的一個名字,類名每每會很長因此別名就方便咱們平時的開發。Mybatis爲咱們內置了一些類的別名:byte、short、int、long、float、double、boolean、char等基礎類型的別名。還有其的封裝類型、String,Object,Map,List等等經常使用的類。
    org.apache.ibatis.type.TypeAliasRegistry這個類中幫咱們內置了別名。能夠看下。自定義別名也是經過這個類進行註冊的。咱們能夠經過settings中typeAliases配置的方式結合@Alias。或者掃描包也能夠的。

TypeHandler

  • 這個接口就四個方法
public interface TypeHandler<T> {

  /**
   * 設置參數是用到的方法
   */
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  T getResult(ResultSet rs, String columnName) throws SQLException;

  T getResult(ResultSet rs, int columnIndex) throws SQLException;

  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}
  • 能夠理解成攔截器。它主要攔截的是設置參數和獲取結果的兩個節點。這個類的做用就是將Java對象和jdbcType進行相互轉換的一個功能。一樣的在org.apache.ibatis.type.TypeHandlerRegistry這個類中mybatis爲咱們提供了內置的TypeHandler。基本上是對於基本數據和分裝對象的轉換。
  • 下面咱們隨便看一個TypeHandler處理細節
public class BooleanTypeHandler extends BaseTypeHandler<Boolean> {

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

  @Override
  public Boolean getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    boolean result = rs.getBoolean(columnName);
    return !result && rs.wasNull() ? null : result;
  }

  @Override
  public Boolean getNullableResult(ResultSet rs, int columnIndex)
      throws SQLException {
    boolean result = rs.getBoolean(columnIndex);
    return !result && rs.wasNull() ? null : result;
  }

  @Override
  public Boolean getNullableResult(CallableStatement cs, int columnIndex)
      throws SQLException {
    boolean result = cs.getBoolean(columnIndex);
    return !result && cs.wasNull() ? null : result;
  }
}
  • setParameter是PreparedStatement進行設置成boolean類型。getResult分別經過三種不一樣方式獲取。在這些方法裏咱們能夠根據本身也無需求進行控制。常見的控制是枚舉的轉換。傳遞參數過程多是枚舉的name,可是傳遞到數據庫中要枚舉的index.這種需求咱們就能夠在TypeHandler中實現。咱們書寫的typeHandler以後並不能被識別,還須要咱們在resultMap中的result標籤中經過typeHandler指定咱們的自定義Handler.

自定義TypeHandler

  • 承接上文咱們說道枚舉的轉換。下面咱們仍是已學生類爲例。學生中性別以前是boolean類型。如今咱們採用枚舉類型。可是數據庫中存的仍是數據,01.

EnumTypeHandler

  • 在TypeHandlerRegister類中申明瞭默認的枚舉類處理器是private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
  String s = rs.getString(columnName);
  return s == null ? null : Enum.valueOf(type, s);
}
  • 咱們經過這個方法能夠看出,這個枚舉處理器適合已枚舉名稱存儲的方式


EnumOrdinalTypeHandler

  • 在Enum中還有一個屬性oridinal。這個表示枚舉中的索引。而後咱們經過查看Mybatis提供的處理器發現有個叫EnumOrdinalTypeHandler。咱們很容易聯想到的就是這個處理器是經過枚舉的因此做爲數據庫內容的。在SexEnum中MALE存儲到數據庫中則爲0.注意這個0不是咱們的index.而是MALE的索引。若是將MALE和FEMAEL調換。那麼MALE索引則爲1.git

  • 由於默認的是EnumTypeHandler。因此想用EnumOrdinalTypeHandler的話咱們要麼在resultMap中sex字段指定該處理器。要不就經過配置文件typeHandlers註冊進來。(將處理器與Java類進行綁定。mybatis遇到這個Java對象的時候就知道用什麼處理器處理)github

<typeHandlers>
    <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.github.zxhtom.enums.SexEnum"/>
</typeHandlers>

SexTypeHandler

  • 上面的不論是經過名稱存儲仍是經過索引存儲都不太知足咱們的需求。咱們想經過咱們的index存儲。那麼這時候咱們就得自定義處理邏輯了。Mybatis處理器都是繼承BaseTypeHandler。由於BaseTypeHandler實現了TypeHandler.因此咱們這裏也就繼承BaseTypeHandler。
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {


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

    @Override
    public SexEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int i = rs.getInt(columnName);
        return SexEnum.getSexEnum(i);
    }

    @Override
    public SexEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        int i = rs.getInt(columnIndex);
        return SexEnum.getSexEnum(i);
    }

    @Override
    public SexEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int i = cs.getInt(columnIndex);
        return SexEnum.getSexEnum(i);
    }
}

typeHandler注意點

  • 在編寫自定義處理器的時候咱們得之處Javatype、jdbctype。二者不是必填。但至少得有一個。正常咱們默認javatype是必填的。
  • 填寫的方式有三種
    • 經過MappedTypes、MappedJdbcTypes分別指定javatype、jdbctype
    • 經過在mybatis-config.xml中配置typeHandlers進行註解。裏面也有這兩個屬性的配置。
    • 經過在mapper.xml的resultmap中再次指定某個字段的typehandler.
  • TypeHandler爲咱們提供了Java到jdbc數據的轉換橋樑。極大的方便了咱們平時的開發。讓咱們開發期間忽略數據的轉換這麼糟心的事情。

加入戰隊sql

# 加入戰隊

微信公衆號

微信公衆號

相關文章
相關標籤/搜索