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文档

相关文章
相关标签/搜索