• mybatis全配置理解


    本文只论mybatis本身,不涉及与spring整合,文中探讨了mybatis最新版本提供的全部配置项的作用。

    首先要了解都有哪些配置项,mybatis的SqlSession来自SqlSessionFactory,SqlSessionFactory来自SqlSessionFactoryBuilder,从SqlSessionFactoryBuilder切入分析

    ...
    public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        try {
          XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
          return build(parser.parse());
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error building SqlSession.", e);
        } finally {
          ErrorContext.instance().reset();
          try {
            reader.close();
          } catch (IOException e) {
            // Intentionally ignore. Prefer previous error.
          }
        }
    }
    ... 

    构造SqlSessionFactoryBuilder用到了XMLConfigBuilder,然后看XMLConfigBuilder

    public Configuration parse() {
        if (parsed) {
          throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        }
        parsed = true;
        parseConfiguration(parser.evalNode("/configuration"));
        return configuration;
    }
    
    private void parseConfiguration(XNode root) {
        try {
          //issue #117 read properties first
          propertiesElement(root.evalNode("properties"));
          Properties settings = settingsAsProperties(root.evalNode("settings"));
          loadCustomVfs(settings);
          typeAliasesElement(root.evalNode("typeAliases"));
          pluginElement(root.evalNode("plugins"));
          objectFactoryElement(root.evalNode("objectFactory"));
          objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
          reflectorFactoryElement(root.evalNode("reflectorFactory"));
          settingsElement(settings);
          // read it after objectFactory and objectWrapperFactory issue #631
          environmentsElement(root.evalNode("environments"));
          databaseIdProviderElement(root.evalNode("databaseIdProvider"));
          typeHandlerElement(root.evalNode("typeHandlers"));
          mapperElement(root.evalNode("mappers"));
        } catch (Exception e) {
          throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
        }
    }
    
    private void settingsElement(Properties props) throws Exception {
        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")));
        @SuppressWarnings("unchecked")
        Class<? extends TypeHandler> typeHandler = (Class<? extends TypeHandler>)resolveClass(props.getProperty("defaultEnumTypeHandler"));
        configuration.setDefaultEnumTypeHandler(typeHandler);
        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"));
        @SuppressWarnings("unchecked")
        Class<? extends Log> logImpl = (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
        configuration.setLogImpl(logImpl);
        configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
    }

    configuration节点为根节点。

    可以配置10个子节点:properties、settings、typeAliases、plugins、objectFactory、objectWrapperFactory、environments、databaseIdProvider、typeHandlers、mappers。

    properties

    这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。例如:

    <!-- mybatis-config.xml -->
    <properties resource="jdbc.properties"></properties> 
    <!-- mybatis-config.xml -->
    <properties>
    	<property name="driver" value="com.mysql.jdbc.Driver"/>
    	<property name="url" value="jdbc:mysql://localhost:3306/a"/>
    	<property name="username" value="root"/>
    	<property name="password" value="root"/>
    </properties>settings 

    settings

    这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

    <!-- mybatis-config.xml -->
    <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="OTHER"/>
      <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    </settings>

    懒加载

    熟悉配置前需要知道什么是懒加载

    public class Order {
    	public Long id;
    	public Long addressId;
    	public Address address;
    }
    
    public class Address {
    	public Long id;
    	public String name;
    }
    
    <!-- addressMapper.xml -->
    <mapper namespace="addressMapperSpace">
    	<select id="getAddressById" parameterType="Long" resultType="Address">
    		select id,name from t_address 
    		where id = #{id}
    	</select>
    </mapper>
    
    <!-- orderMapper.xml -->
    <mapper namespace="...">
    	<resultMap id="orderMap" type="Order">
    		<id property="id" column="id" />
    		<association property="address" column="address_id"
    			select="addressMapperSpace.getAddressById" />
    	</resultMap>
    	<select id="getOrderById" resultMap="orderMap" parameterType="Long">
    		select id,address_id from t_order
    		where id = #{id}
    	<select>
    </mapper>
    

    如果是懒加载,那么访问order的address属性时才会去查询address。

    参数介绍

    参数

    官方中文描述

    理解

    可选值

    默认值

    cacheEnabled

    全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。

    mybatis二级缓存开关,不支持集群环境,设置成false防止意外。

    true | false

    true

    lazyLoadingEnabled

    延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态

    可以不设置

    true | false

    false

    aggressiveLazyLoading

    当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyLoadTriggerMethods).

    当设置为true时,懒加载的对象可能被任何懒属性全部加载;否则,每个属性按需加载。一般不用。

    可以不设置

    true | false

    false (true in ≤3.4.1)

    lazyLoadTriggerMethods

    指定对象的哪个方法触发一次延迟加载。

    在lazyLoadingEnabled=true时有效,调用本方法会使得所有延迟加载属性被加载,如果有多个懒加载属性,可以使用这个方法把所有懒加载属性一起加载了。

    可以不设置

    用逗号分隔的方法列表。

    equals,clone,hashCode,toString

    proxyFactory

    指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。

    mybatis延迟加载用的工具,旧版本使用的是CGLIB动态代理技术,新版本支持使用JAVASSIST(Javassist是一个运行时编译库,他能动态的生成或修改类的字节码)来完成。

    可以不设置

    CGLIB | JAVASSIST

    JAVASSIST (MyBatis 3.3 or above)

    multipleResultSetsEnabled

    是否允许单一语句返回多结果集(需要兼容驱动)。

    sql与ResultSet一对多的用法, 没找到用法。

    可以不设置

    true | false

    true

    useColumnLabel

    使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。

    在Select字段的时候使用AS,用得上,由于默认true。

    可以不设置

    true | false

    true

    useGeneratedKeys

    允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。

    我们使用mysql数据库自增主键,在xml的insert块中如果使用useGeneratedKeys来获得生成的主键,那这个属性必须设置成true。如果使用以下方法,那也可以不设置。

    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">

     SELECT LAST_INSERT_ID() </selectKey>

    true | false

    false

    autoMappingBehavior

    指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。

    如果修改成FULL,会由于没及时更新model导致映射失败。

    可以不设置

    NONE, PARTIAL, FULL

    PARTIAL

    autoMappingUnknownColumnBehavior

    指定发现自动映射目标未知列(或者未知属性类型)的行为。

    • NONE: 不做任何反应

    • WARNING: 输出提醒日志 ('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior'的日志等级必须设置为 WARN)

    • FAILING: 映射失败 (抛出 SqlSessionException)

    可以不设置

    NONE, WARNING, FAILING

    NONE

    defaultExecutorType

    配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。

    1.设为"SIMPLE", 在执行dao.save()时,就相当于JDBC的stmt.execute(sql);

    2.设为"REUSE", 在执行dao.save()时,相当于JDBC重用一条sql,再通过stmt传入多项参数值,然后执行stmt.executeUpdate()或stmt.executeBatch();重用sql的场景不太常见,因此用SIMPLE就可以了。

    3.设为"BATCH", 在执行dao.save()时,相当于JDBC语句的 stmt.addBatch(sql),即仅仅是将执行SQL加入到批量计划。 所以此时不会抛出主键冲突等运行时异常,而只有临近commit前执行stmt.execteBatch()后才会抛出异常。

    可以不设置

    SIMPLE REUSE BATCH

    SIMPLE

    defaultStatementTimeout

    设置超时时间,它决定驱动等待数据库响应的秒数。

    这是以秒为单位的全局sql超时时间设置,当超出了设置的超时时间时,会抛出SQLTimeoutException。建议设置一个合理值。

    任意正整数

    Not Set (null)

    defaultFetchSize

    为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。

    mysql不支持fetchSize。

    一般使用分页插件即可。

    可以不设置

    任意正整数

    Not Set (null)

    safeRowBoundsEnabled

    允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false。

    使用场景:session.select("...", null, new RowBounds(1, 2),resultHandler);

    一般使用分页插件即可。

    可以不设置

    true | false

    false

    safeResultHandlerEnabled

    允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为false。

    使用场景:session.select("...", null, new RowBounds(1, 2),resultHandler);
    一般使用分页插件即可。

    可以不设置

    true | false

    true

    mapUnderscoreToCamelCase

    是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。

    驼峰命名映射,手写mapper不去写resultMap时推荐开启。使用mybatis-generator时,不开启也ok。

    true | false

    false

    localCacheScope

    MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。

    一级缓存在spring中基本也用不上,可以不设置

    SESSION | STATEMENT

    SESSION

    jdbcTypeForNull

    当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。

    正常情况下我们都配了。

    可以不设置

    JdbcType 常量. 大多都为: NULL, VARCHAR and OTHER

    OTHER (java.lang.Object)

    defaultScriptingLanguage

    指定动态 SQL 生成的默认语言。

    虽然官方名称叫做LanguageDriver,其实叫做解析器可能更加合理。MyBatis 从 3.2 开始支持可插拔的脚本语言,因此你可以在插入一种语言的驱动(language driver)之后来写基于这种语言的动态 SQL 查询比如mybatis除了XML格式外,还提供了mybatis-velocity,允许使用velocity表达式编写SQL语句。可以通过实现LanguageDriver接口的方式来插入一种语言。

    可以不设置

    一个类型别名或完全限定类名。

    org.apache.ibatis.scripting.xmltags.XMLLanguageDriver

    defaultEnumTypeHandler

    指定 Enum 使用的默认 TypeHandler 。 (从3.4.5开始)

    默认的EnumTypeHandler存入数据库的是枚举的name,

    mybatis还提供了EnumOrdinalTypeHandler存入数据库的是枚举的位置。

    这俩都不太好用,如果想要把数据库查询结果与枚举自动转换,可以自定义typeHandler来实现。在查询或操作数据时以枚举传输优势并不大,只提供对应的枚举也可满足需求。

    可以不设置

    一个类型别名或完全限定类名。

    org.apache.ibatis.type.EnumTypeHandler

    callSettersOnNulls

    指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。

    假设将数据从DB中查询出来如果将字段映射为Map,而不想封装成Bean。默认情况下,Mybatis对Map的解析生成, 如果值(value)为null的话,那么key也不会被加入到map中.
    于是对Map遍历时,key就遍历不到。部分情况会有需要key存在,value=null的情况,依据多数实际场景来看,使用默认值false没问题。

    可以不设置

    true | false

    false

    returnInstanceForEmptyRow

    当返回行的所有列都是空时,MyBatis默认返回null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (i.e. collectioin and association)。(从3.4.2开始)

    查询结果没有的时候,返回null是合理的,返回一个空对象容易引起误会。

    不要设置

    true | false

    false

    logPrefix

    指定 MyBatis 增加到日志名称的前缀。

    日志前缀,要不要看个人喜好。

    可以不设置

    任何字符串

    Not set

    logImpl

    指定 MyBatis 所用日志的具体实现,未指定时将自动查找。

    不要设置

    SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

    Not set

    vfsImpl

    指定VFS的实现

    VFS主要用来加载容器内的各种资源,比如jar或者class文件。mybatis提供了2个实现 JBoss6VFS 和 DefaultVFS,并提供了用户扩展点,用于自定义VFS实现,加载顺序是自定义VFS实现 > 默认VFS实现 取第一个加载成功的,默认情况下会先加载JBoss6VFS,如果classpath下找不到jboss的vfs实现才会加载默认VFS实现。
    可以不设置

    自定义VFS的实现的类全限定名,以逗号分隔。

    Not set

    useActualParamName

    允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的工程必须采用Java 8编译,并且加上-parameters选项。(从3.4.1开始)

    mybatis的全局配置useActualParamName决定了mapper中参数的写法,默认为true。此时无需再使用@Param。

    Order getOrderByCondition (Long id,Long addressId)

    <select id="getOrderByCondition" resultType="Order" > select * from t_order where id = #{id} and addressId = #{addressId} </select>

    如果是false那么可写成

    <select id="getOrderByCondition" resultType="Order" > select * from t_order where id = #{0} and addressId = #{1} </select>

    使用这个特性必须在jdk1.8场景。这是因为:在Java 8之前的版本,代码编译为class文件后,方法参数的类型是固定的,但参数名称却丢失了,这和动态语言严重依赖参数名称形成了鲜明对比。现在,Java 8开始在class文件中保留参数名,给反射带来了极大的便利。jdk8增加了类Parameter。

    可以不设置

    true | false

    true

    configurationFactory

    指定一个提供Configuration实例的类。 这个被返回的Configuration实例用来加载被反序列化对象的懒加载属性值。 这个类必须包含一个签名方法static Configuration getConfiguration(). (从 3.2.3 版本开始)

    此时mybatis全局的Configuration将被开发者手动指定。

    建议不设置

    类型别名或者全类名.

    Not set

    typeAliases

    类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,原理是用hashMap关联,存在的意义仅在于用来减少类完全限定名的冗余。例如:

    <!-- mybatis-config.xml -->
    <typeAliases>
      <typeAlias alias="OrderMain" type="order.center.domain.OrderMain"/>
    </typeAliases>
    <!-- mybatis-config.xml -->
    <typeAliases>
      <package name="order.center.domain"/>
    </typeAliases>

    typeHandlers

    无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。

    可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个 JDBC 类型。

    下面是一个处理javaType=com.alibaba.fastjson.JSON时的例子

    public class ExampleTypeHandler extends BaseTypeHandler<JSON> {
      @Override
      public void setNonNullParameter(PreparedStatement ps, int i, JSON parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i,parameter.toJSONString());
      }
    
      @Override
      public JSON getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return JSON.parseObject(rs.getString(columnName));
      }
    
      @Override
      public JSON getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return JSON.parseObject(rs.getString(columnIndex));
      }
    
      @Override
      public JSON getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return JSON.parseObject(cs.getString(columnIndex));
      }
    }
    <!-- mybatis-config.xml -->
    <typeHandlers>
      <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
    </typeHandlers>
    <!-- Ordermapper.xml中使用 -->
    <result column="order_json" typeHandler="org.mybatis.example.ExampleTypeHandle" jdbcType="VARCHAR" property="orderJson" />

    objectFactory

    MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。比如:

    // ExampleObjectFactory.java
    public class ExampleObjectFactory extends DefaultObjectFactory {
      public Object create(Class type) {
        return super.create(type);
      }
      public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {
        return super.create(type, constructorArgTypes, constructorArgs);
      }
      public void setProperties(Properties properties) {
        super.setProperties(properties);
      }
      public <T> boolean isCollection(Class<T> type) {
        return Collection.class.isAssignableFrom(type);
      }
    }
    <!-- mybatis-config.xml -->
    <objectFactory type="org.mybatis.example.ExampleObjectFactory">
      <property name="someProperty" value="100"/>
    </objectFactory>
    

    一般情况很少会使用到自定义ObjectFactory,如果需要使用的话,建议是在对象创建时需要做一些操作,或前或后,用于改变或者丰富被创建对象。

    objectWrapperFactory

    最新的官方文档中已经找不到这个配置项。原用来提供自定义的ObjectWrapper

    plugins

    MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

    • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

    • ParameterHandler (getParameterObject, setParameters)

    • ResultSetHandler (handleResultSets, handleOutputParameters)

    • StatementHandler (prepare, parameterize, batch, update, query)

    这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为如果在试图修改或重写已有方法的行为的时候,你很可能在破坏 MyBatis 的核心模块。 这些都是更低层的类和方法,所以使用插件的时候要特别当心。

    通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

    例如配置pageHelper:

    <!-- mybatis-config.xml -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>
            <property name="offsetAsPageNum" value="false"/>
            <property name="rowBoundsWithCount" value="false"/>
            <property name="pageSizeZero" value="true"/>
            <property name="reasonable" value="false"/>
            <property name="supportMethodsArguments" value="false"/>
            <property name="returnPageInfo" value="none"/>
        </plugin>
    </plugins>

    environments

    MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者共享相同 Schema 的多个生产数据库, 想使用相同的 SQL 映射。许多类似的用例。

    不过要记住:尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选择其一。

    所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:

    • 每个数据库对应一个 SqlSessionFactory 实例

    为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。可以接受环境配置的两个方法签名是:

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

    如果忽略了环境参数,那么默认环境将会被加载,如下所示:

    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);

    环境元素定义了如何配置环境。

    <!-- mybatis-config.xml -->
    <environments default="development">
      <environment id="development">
        <!--Mybatis管理事务是分为两种方式:
       (1)使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
       (2)使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,而是让程序的容器(JBOSS,WebLogic)来实现对事务的管理
       -->
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
          <!-- 可以直接用properties也可以在这配 -->
          <property name="driver" value="${driver}"/>
          <property name="url" value="${url}"/>
          <property name="username" value="${username}"/>
          <property name="password" value="${password}"/>
        </dataSource>
      </environment>
      <environment id="test">
        <!-- mybatis提供的区分不同环境的数据库连接配置 -->
      </environment>
    </environments>

    databaseIdProvider

    MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。 为支持多厂商特性只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:

    我们实际使用中,不同数据库大概率是不同数据源,很低概率出现同一个mapper两种数据库使用,因此这个配置项几乎不可能用上。

    <!-- mybatis-config.xml -->
    <databaseIdProvider type="DB_VENDOR">
      <property name="SQL Server" value="sqlserver"/>
      <property name="DB2" value="db2"/>        
      <property name="Oracle" value="oracle" />
      <property name="Mysql" value="mysql" />
    </databaseIdProvider>
    <!-- mapper.xml -->
    <insert id="insertTest" ...>
        INSERT INTO users(name, age) VALUES('zhangsan', 1), ('wangwu', 2), ('zhaoliu', 3); 
    </insert>
    <insert id="insertTest" ... databaseId="oracle">
      INSERT ALL INTO users VALUES('zhangsan', 1)
    	INTO users  VALUES ('wangwu', 2)
    	INTO users  VALUES ('zhaoliu', 3);
    </insert>

    mappers

    既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要定义 SQL 映射语句了。但是首先我们需要告诉 MyBatis 到哪里去找到这些语句。 Java 在自动查找这方面没有提供一个很好的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等。例如:

    <!-- mybatis-config.xml 使用spring后可以在sqlSessionFactory里配置*.xml-->
    <mappers>
      <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
      <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
      <mapper resource="org/mybatis/builder/PostMapper.xml"/>
    </mappers>
    <!-- mybatis-config.xml 此方法mapper接口和xml必须同名放在一起-->
    <mappers>
      <package name="org.mybatis.builder"/>
    </mappers>
    <!-- mybatis-config.xml 绝对路径,不可用-->
    <mappers>
      <mapper url="file:///var/mappers/AuthorMapper.xml"/>
      <mapper url="file:///var/mappers/BlogMapper.xml"/>
      <mapper url="file:///var/mappers/PostMapper.xml"/>
    </mappers>
    

     

  • 相关阅读:
    【学习】CodeUi
    【C#】权限修饰符
    链表_初步认识
    关于mysql8.0及以上版本连接navicat时候报错(密码加密方式需要修改)
    docker 运行mysql最新版本用navicat连接报错:1251
    spring5的基本组成(6个模块)
    关于java中设计原则总结(7)
    java中String中的endsWith()方法
    mysql中基本的语句
    mysql中索引类型
  • 原文地址:https://www.cnblogs.com/caizhiqin/p/9883226.html
Copyright © 2020-2023  润新知