MyBatis配置與重要組件梳理

1、爲何要MyBatis配置文件

其實MyBatis配置文件咱們已經不多使用到,由於咱們通常不會只是使用MyBatis,而是和Spring一塊兒使用。html

在Spring中咱們通常會配置一個SqlSessionFactoryBean來建立SqlSessionFactory,而通常不會經過解析配置文件來建立SqlSessionFactory。java

可是配置文件很重要,由於它能夠幫助咱們瞭解MyBatis中的組件,更好的理解MyBatis的流程和原理。mysql

因此咱們首先介紹一下MyBatis的配置文件,而後介紹手動建立SqlSessionFactory,而後介紹Spring和SpringBoot是如何建立SqlSessionFactory。git

通常一個數據庫對應一個SqlSessionFactory實例github

經過SqlSessionFactory獲取到SqlSession就可以對數據庫進行操做。spring

1.1 configuration中元素順序

  1. properties
  2. settings
  3. typeAliases
  4. typeHandlers
  5. objectFactory
  6. objectWrapperFactory
  7. plugins
  8. environments
  9. databaseIdProvider
  10. mappers

1.2 properties與environments

<?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="dbconfig.properties">
        <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
        <property name="username" value="${username:tim}"/>
        <property name="password" value="${password:123456}"/>
    </properties>

    <!--default設置爲environment的id就能夠切換不一樣的environment-->
    <environments default="development">
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${test.jdbc.driver}" />
                <property name="url" value="${test.jdbc.url}" />
                <property name="username" value="${test.jdbc.username}" />
                <property name="password" value="${test.jdbc.password}" />
            </dataSource>
        </environment>

        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${mybatis.jdbc.driver}" />
                <property name="url" value="${mybatis.jdbc.url}" />
                <property name="username" value="${mybatis.jdbc.username}" />
                <property name="password" value="${mybatis.jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
</configuration>

properties設置能夠訪問的屬性,3.4以後能夠設置默認值 properties的resource能夠經過文件導入properties,key=value形式sql

environments能夠包含多個environment,可是隻會使用其中一個。數據庫

1.3 environment的transactionManager

environment的transactionManager配置事務管理器:apache

  1. JDBC(JdbcTransactionFactory)
  2. MANAGED(ManagedTransactionFactory)

其實JDBC和MANAGED是在Configuration配置類的類型別名註冊器中註冊的別名 其對應的類分別是JdbcTransactionFactory、ManagedTransactionFactoryspringboot

在MyBatis的Configuration類中的構造函數中就能夠看到:

typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

JDBC直接使用了JDBC的提交和回滾設置,它依賴於從數據源獲得的鏈接(Collection)來管理事務做用域

MANAGED配置什麼都沒作,而是讓容器來管理事務的整個生命週期

若是你正在使用 Spring + MyBatis,則沒有必要配置事務管理器, 由於Spring模塊會使用自帶的管理器來覆蓋前面的配置。

1.4 environment的dataSource

datasource就是數據源,MyBatis有三種內建的數據源類型UNPOOLED、POOLED、JNDI

都是數據源別名,都在MyBatis的Configuration中註冊了對應的類:

typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

對應JNDI多少幾句,JNDI(Java Naming and Directory Interface,Java命名和目錄接口),JNDI是Java平臺的一個標準擴展,提供一組接口、類和關於命名空間的概念。

簡單來講就是,資源提供者想要其它人使用這個資源,就把資源放在一個容器中,並給這個資源一個名稱。

其餘要使用的人經過名稱使用lookup就能夠查找到資源,最多見的就算Tomcat配置一個Datasource,在Servlet中就可使用。

Context context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("name")

1.5 typeAliases、typeHandlers

<?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>
    <typeAliases>
        <typeAlias alias="Author" type="org.curitis.bean.Author"/>
        <package name="org.curitis.bean"/>
    </typeAliases>
    <typeHandlers>
        <typeHandler handler="org.curitis.handler.ExampleTypeHandler"/>
        <package name="org.curitis.handler"/>
    </typeHandlers>
</configuration>

typeAliases、typeHandlers均可以指定類或者直接指定要掃描的包,通常2種配置二選一就能夠,若是2種都要,package在後。

1.6 typeAliases

typeAliases是爲Java類型設置一個短的名字,它只和XML配置有關,存在的意義僅在於用來減小類徹底限定名的冗餘。

也可使用註解方式:

@Alias("user")
public class User {
    
}

1.7 typeHandlers

typeHandlers用於處理JDBC類型到Java類型之間的轉換,例如枚舉類型轉換爲數字存儲和讀取。

2中方式建立本身的typeHandlers:

  1. 實現:org.apache.ibatis.type.TypeHandler
  2. 繼承:org.apache.ibatis.type.BaseTypeHandler
public class StatusTypeHandler implements TypeHandler<StatusType> {

    @Override
    public void setParameter(PreparedStatement ps, int i, StatusType statType, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, statType.getId());
    }

    @Override
    public StatusType getResult(ResultSet resultSet, String columnName) throws SQLException {
        return StatusType.getInstance(resultSet.getInt(columnName));
    }

    @Override
    public StatusType getResult(ResultSet resultSet, int columnIndex) throws SQLException {
        return StatusType.getInstance(resultSet.getInt(columnIndex));
    }

    @Override
    public StatusType getResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
        return StatusType.getInstance(callableStatement.getInt(columnIndex));
    }
}

2、plugins、mappers

<?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>
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>
            <!-- 默認false,設置爲true時,會將RowBounds第一個參數offset當成pageNum頁碼使用 -->
            <property name="offsetAsPageNum" value="true"/>
            <!-- 默認false,設置爲true時,使用RowBounds分頁會進行count查詢 -->
            <property name="rowBoundsWithCount" value="true"/>
            <!-- 設置爲true時,若是pageSize=0或者RowBounds.limit = 0就會查詢出所有的結果 -->
            <property name="pageSizeZero" value="true"/>
            <!-- 默認false,啓用合理化時,若是pageNum<1會查詢第一頁,若是pageNum>pages會查詢最後一頁 -->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>
    <mappers>
        <mapper resource="org/curitis/mapper/AuthorMapper.xml"/>
        <mapper url="file:///F:/mappers/AuthorMapper.xml"/>
        <mapper class="org.curitis.mapper.AuthorMapper"/>
        <package name="org.curitis.mapper"/>
    </mappers>
</configuration>

plugins就是配置插件,就是實現了MyBatis的Interceptor的類。

如上所示,mapper配置方式多樣,處理使用xml配置還可使用@Mapper註解。

值得注意的是Mapper的xml配置文件的路徑最好和Mapper接口的路徑同樣,不然,若是使用手動建立SqlSessionFactory的時候就可能出現下面的錯誤。

Mapped Statements collection does not contain value for xxx

通常看到Mapped Statements相關的問題,就能夠調試定位問題,斷點打到Configuration的getMappedStatement方法中,看一下mappedStatements有沒有要執行的方法。

帶namespace的和不帶namespace的方法都有。

3、settings

<?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>
    <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="autoMappingUnknownColumnBehavior" value="WARNING"/>
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <setting name="defaultStatementTimeout" value="25"/>
        <setting name="defaultFetchSize" value="100"/>
        <setting name="safeRowBoundsEnabled" value="false"/>
        <setting name="mapUnderscoreToCamelCase" value="false"/>
        <setting name="localCacheScope" value="SESSION"/>
        <setting name="jdbcTypeForNull" value="NULL"/>
        <setting name="lazyLoadTriggerMethods" value="equals,clone"/>
    </settings>
</configuration>
<setting name="logImpl" value="STDOUT_LOGGING" />

打印日誌,STDOUT_LOGGING是輸出到控制檯,還可使用SLF4J、LOG4J、LOG4J2等。

<setting name="returnInstanceForEmptyRow" value="true" />

returnInstanceForEmptyRow默認爲false,當列全爲空的時候,會返回一個null,這樣若是是列表到客戶端的時候可能就是[null],不少客戶端不能處理,而且沒有解決異常就會出問題。

因此能夠設置true,返回一個空實例。

MyBatis基礎配置 MyBatis擴展配置

4、手動建立SqlSessionFactory

爲了更好的理解MyBatis的組件,以及後面在Spring中使用MyBatis,咱們先看一下手動建立SqlSessionFactory。

SqlSessionFactory屬性

4.1 經過xml文件建立

@Test
public void sessionFactory() throws IOException {
    String configXml = "mybatis-config.xml";
    InputStream stream = Resources.getResourceAsStream(configXml);
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(stream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    User user = new User();
    user.setName("tim");
    sqlSession.insert("saveUser",user);
    sqlSession.close();
}

mybatis-config.xml就是Mybatis的配置文件,放在resources目錄下就能夠了。

xml文件解析是經過MyBatis的XMLConfigBuilder類實現

這裏主要是看SqlSessionFactory就不貼User,UserMapper以及對應的xml文件了。

只須要注意saveUser是UserMapper的方法,在xml文件中有對應的id。

4.2 經過代碼建立

@Test
public void config(){
    PooledDataSource dataSource= new PooledDataSource();
    dataSource.setDriver("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
    dataSource.setUsername("tim");
    dataSource.setPassword("123456");

    Environment environment = new Environment("dev", new JdbcTransactionFactory(), dataSource);

    Configuration config= new Configuration(environment);
    config.addMappers("org.curitis.mapper");

    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(config);

    SqlSession sqlSession = sqlSessionFactory.openSession(false);
    User user = new User();
    user.setName("config");
    sqlSession.update("org.curitis.mapper.UserMapper.saveUser",user);
    sqlSession.commit();
    sqlSession.close();
}

除了經過xml建立,還能夠經過代碼直接建立,若是理解了上面的代碼,對於下面Spring中使用Mybatis的思路就清晰多了。

咱們能夠看到經過代碼建立SqlSessionFactory比xml建立更具靈活性,例如咱們可使用其餘的數據庫鏈接池。

5、Spring中建立SqlSessionFactory

<?xml version="1.0" encoding="UTF-8"?>        
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">

    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:dbconfig.properties</value>
            </list>
        </property>
    </bean>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="${mybatis.jdbc.driver}" />
        <property name="username" value="${mybatis.jdbc.username}" />
        <property name="password" value="${mybatis.jdbc.password}" />
        <property name="initialSize" value="5" />
        <property name="minIdle" value="5" />
        <property name="maxActive" value="10" />
        <property name="maxWait" value="10000" />
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath:org/curitis/mapper/*.xml"/>
        <property name="typeAliasesPackage" value="org.curitis.bean"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <mybatis:scan base-package="org.curitis.mapper" factory-ref="sqlSessionFactory" />
    
</beans>

經過Spring使用MyBatis的配置基本就是像上面這樣,喜歡註解和自動配置的朋友不要着急,一步一步來,它們都是在這個基礎上發展而來的,因此弄清楚上面配置,其餘的自動配置固然也不在話下。

其餘的不用多說,只須要看SqlSessionFactoryBean這個類和包掃描的部分。

5.1 SqlSessionFactoryBean

先看SqlSessionFactoryBean中MyBatis相關經常使用屬性:

屬性 說明
dataSource 數據源,應該很是熟悉
configLocation MyBatis的配置文件資源
mapperLocations Mapper對應的xml文件位置
typeAliasesPackage 要配置別名包,會自動添加
typeHandlersPackage typeHandler包位置

看上面的屬性是否是和前面介紹MyBatis配置的組件對應上了。

SqlSessionFactoryBean一看就能夠猜是一個Spring的FactoryBean,熟悉Spring的同窗清楚FactoryBean獲取對象是調用getObject方法。

同時SqlSessionFactoryBean還實現了InitializingBean,因此設置完屬性以後會調用afterPropertiesSet方法。

在afterPropertiesSet方法中調用了buildSqlSessionFactory,buildSqlSessionFactory就是具體構建SqlSessionFactory的方法。

這裏不詳細介紹了,有興趣,斷點打進去調試一下就清楚了。

5.2 包掃描

<mybatis:scan base-package="org.curitis" factory-ref="sqlSessionFactory" />

上面是配置包掃描,在Spring中看到xml帶有前綴的,找NamespaceHandler就對了,通常就是前綴加上NamespaceHandler這個類,例如MvcNamespaceHandler、DubboNamespaceHandler。

mybatis有點不按常理出牌,他就叫NamespaceHandler:

public class NamespaceHandler extends NamespaceHandlerSupport {
  @Override
  public void init() {
    registerBeanDefinitionParser("scan", new MapperScannerBeanDefinitionParser());
  }
}

能夠看到註冊了一個MapperScannerBeanDefinitionParser類來解析mybatis:scan

MapperScannerBeanDefinitionParser建立了了一個MapperScannerConfigurer實例,並添加到Spring中,具體咋建立的key看parseInternal方法。

搞了半天mybatis:scan是建立了一個MapperScannerConfigurer實例,徹底能夠直接建立一個MapperScannerConfigurer,那用那麼多彎彎道道的。

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="org.curitis" />
</bean>

MapperScannerConfigurer發揮器做用的地方在postProcessBeanDefinitionRegistry方法中,有興趣的朋友能夠本身研究。

除了xml配置,咱們還能夠經過註解:

@MapperScan("org.curitis.mapper")
@MapperScan("org.curitis.*.mapper")
@MapperScan({"org.curitis.user","org.curitis.order"})

6、SpringBoot自動配置

springboot咱們使用mybatis-spring-boot-starter,它依賴mybatis-spring-boot-autoconfigure這個包。

自動配置的關鍵類是MybatisAutoConfiguration,它上面有註解:

@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class }) 表示若是當前classpath路徑下面存在SqlSessionFactory.class和SqlSessionFactoryBean.class這兩個類,才知足將當前配置裝載到spring容器中的必要條件。

@ConditionalOnSingleCandidate(DataSource.class) 表示當前上下文中有一個DataSource實例的時候才知足將當前配置裝載到spring容器中的必要條件

@AutoConfigureAfter(DataSourceAutoConfiguration.class) 表示配置裝載在DataSourceAutoConfiguration配置裝載以後,這個好理解,由於配置的時候依賴DataSource。

有興趣能夠看一下MybatisAutoConfiguration這個類怎樣建立SqlSessionFactory。

7、文檔

MyBatis文檔

相關文章
相關標籤/搜索