MyBatis详解3.MyBatis配置详解

字节跳动飞书内推!
北京、杭州、武汉、广州、深圳、上海,六大城市等你来投。
感兴趣的朋友可以私我咨询&内推,也可以通过链接直接投递
海量HC,极速响应,快来和我成为同事吧。
今日头条、抖音、Tik Tok也可以内推~

点击进入我的博客

MyBatis详解1.概述
MyBatis详解2.MyBatis使用入门
MyBatis详解3.MyBatis配置详解
MyBatis详解4.映射器Mapper
MyBatis详解5.动态SQL
MyBatis详解6.MyBatis技术内幕
MyBatis详解7.插件
MyBatis详解8.集成Spring

1 MyBatis XML配置文件层次结构

以下的图片展示了MyBatis的全部配置元素


MyBatis配置文件层次结构

2 properties元素

properties是一个配置属性的元素,让我们能在配置文件的上下文中使用它,MyBatis提供3种配置方式。

  • property子元素。
  • properties配置文件。
  • SqlSessionFactoryBuilder使用Properties文件构建。
property子元素
    <property name="driver" value="com.mysql.jdbc.Driver"/>
properties配置文件

一般情况下,我们会使用一个单独的properties配置文件来配置属性值,以方便我们在多个配置文件中重复使用它们,也方便日后维护和随时修改。我们可以通过${key}的形式,取出在配置文件中配置的值。

<configuration>
    <!-- 引入配置文件 -->
    <properties resource="datasource.properties"/>

    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!-- 使用配置文件中的属性 -->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
SqlSessionFactoryBuilder使用Properties文件构建

出于安全考虑,properties配置文件中的账号密码等元素可能是加密的,这个时候就需要对加密的元素进行处理。

    public static void func() throws Exception {
        Properties properties = new Properties();
        properties.load(Resources.getResourceAsStream("datasource.properties"));
        // 对原账号密码解密
        properties.setProperty("username", decode(properties.getProperty("username")));
        properties.setProperty("password", decode(properties.getProperty("password")));

        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        // SqlSessionFactoryBuilder可以使用一个InputStream和一个Properties构建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is, properties);
    }
三种方式的优先级

MyBatis支持的3种配置方式可能同时出现,并且属性还会重复配置,MyBatis将按照下面的顺序来加载:

  1. 在properties元素体内指定的属性首先被读取。
  2. 根据 properties元素中的resource属性读取类路径下属性文件,或者根据ur属性指定的路径读取属性文件,并覆盖已读取的同名属性。
  3. 读取作为build()方法参数传递的属性,并覆盖已读取的同名属性。

因此,通过build()方法参数传递的属性具有最高优先级,resource/url属性中指定的配置文件
次之,最低优先级的是 properties属性中指定的属性。因此,我们尽量不要使用混合的方式来定义配置,首选的方式是使用properties文件。

3 settings设置

settings(设置)在MyBatis中是最复杂的配置,它会改变 MyBatis运行时的行为。

设置参数 描述 有效值 默认值
cacheEnabled 该配置影响所有映射器中配置的缓存全局开关 true、 false true
lazyLoadingEnabled 延迟加载的全局开关,当它开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态 true、false false
aggressiveLazyLoading 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载 true、 false true
multipleresultSetsEnabled 是否允许单一语句返回多结果集(需要兼容驱动) true、 false true
useColumnLabel 使用列标签代替列名。不同的驱动在这方面会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果 true、 false true
useGeneratedKeys 允许JDBC支持自动生成主键,需要驱动兼容。如果设置为true,则这个设置强制使用自动生成主键 true、fase false
autoMappingBehavior 指定 MyBatis应如何自动映射列到字段或属性:NONE表示取消自动映射、PARTIAL只会自动映射没有定义嵌套结果集映射的结果集、FULL会自动映射任意复杂的结果集 NONE、 PARTIAL、FULL PARTIAL
defaultExecutorType 配置默认的执行器:SIMPLE是普通的执行器、REUSE执行器会重用预处理语句(prepared statements)、BATCH执行器将重用语句并执行批量更新 SIMPLE、 REUSE、SIMPLE SIMPLE
defaultStatementTimeout 设置超时时间,它决定驱动等待数据库响应的秒数。当没有设置的时候它取的就是驱动默认的时间 any positive integer Not set(null)
safeRowBoundsEnabled 允许在嵌套语句中使用分页(Row Bounds) true、 false False
mapUnderscoreToCamelCase 是否开启自动驼峰命名规则映射,即从经典数据库列名 A_COLUMN到经典Java属性名 aColumn的类似映射 true、false false
localCacheScope MyBatis利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。若设置值为STATEMENT,本地 STATEMENT会话仅用在语句执行上,对相同 SqlSession的不同调用将不会共享数据 SESSION、STATEMENT SESSION
jdbcTypeForNull 当没有为参数提供特定的JDBC类型时,为空值指定JDBC类型。某些驱动需要指定列的JDBC类型,多数情况情况直接使用一般类型即可,比如NULL、 VARCHAR、OTHER JdbcType枚举 OTHER
lazyLoadTriggerMethods 指定对象的方法触发一次延迟加载 如果是一个方法列表,我们则用逗号将它们隔开 equals, clone, hashCode, toString
defaultScriptingLanguage 指定动态SQL生成的默认语言 你可以配置类的别名或者类的全限定名 org....XMLDynamicLanguageRiver
callSettersOnNulls 指定当结果集中值为null的时候是否调用映射对象的setter(map对象时为put)方法,这对于有Map.keySet()依赖或null值初始化的时候是有用的。注意基本类型是不能设置成null的 true、 false false
logPrefix 指定MyBatis增加到日志名称的前缀 任何字符串 没有设置
logImpl 指定 MyBatis所用日志的具体实现,未指定时将自动查找 SLF4J、LOG4J、JDK LOGGING、NO LOGGING 没有设置
proxyFactory 指定MyBatis创建具有延迟加载能力的对象所用到的代理工具 CGLIB、JAVASSIST (3.3.0以上版本是)JAVASSIST,否则CGLIB

4 typeAliases类型命名

别名(typeAliases)是一个指代的名称。因为我们遇到的类全限定名过长,所以我们希望用一个简短的名称去指代它,而这个名称可以在MyBatis上下文中使用,在 MyBatis中别名是不分大小写的。一个 typeAliases的实例是在解析配置文件时生成的,然后长期保存在 Configuration对象中,这样就没有必要运行的时候再次生成它的实例了。

系统定义别名

通过org.apache.ibatis.type.TypeAliasRegistry可以查看所有系统定义的别名,主要是基本数据类型、字符串、基本数据类型数组、日期、容器类。

通过XML自定义别名

在mybatis-config.xml中通过<typeAliases>元素可以自定义别名。

    <typeAliases>
        <typeAlias type="com.ankeetc.spring.domain.UserDomain" alias="user"/>
    </typeAliases>
通过注解的方式自定义别名
    <!-- 通过package扫描包 -->
    <typeAliases>
        <package name="com.ankeetc.spring.domain"/>
    </typeAliases>
@Alias("user")
public class UserDomain {
}

当配合上面的配置,MyBatis就会自动扫描包,将扫描到的类装载到上下文中。如果配置了包扫描的路径,而没有注解@Alias的类也会被MyBatis装载,MyBatis会自动把类名的第一个字母变为小写,作为MyBatis的别名。

5 typeHandler类型处理器

MyBatis在预处理语句(PreparedStatement)中设置一个参数或者从结果集(ResultSet)中取出一个值时,都会用注册了的typeHandler进行处理。typeHandler常用的配置为Java类型(javaType)、JDBC类型(jdbcType)。typeHandler的作用就是将参数从javaType转化为 jdbcType,或者从数据库取出结果时把jdbcType转化为javaType。

5.1 系统定义的typeHandler

在org.apache.ibatis.type.TypeHandlerRegistry中MyBatis定义了很多系统内部的typeHader,主要是基本类型、字符串、时间类型、枚举类型的处理。

5.2 自定义typeHandler

继承BaseTypeHandler或实现TypeHandler

对于自定义typeHandler的要求是必须实现接口org.apache.ibatis.type.TypeHandler,更简单的方式是继承已经实现了该接口的实现类org. apache.ibatis.type.BaseTypeHandler

确定拦截类型

可以在自定义typeHandler里用注解配置@MappedTypes@MappedJdbcTypes,也可以在<typeHandler>元素中指定。

  • @MappedTypes定义的是JavaType类型,可以指定哪些Java类型被拦截;
  • @MappedJdbcTypes定义的是JdbcType类型,取值范围在枚举类org.apache.ibatis.type.JdbcType中找到。
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class MyStringTypeHandler implements TypeHandler<String> {
    @Override
    public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        System.out.println("MyStringTypeHandler#setParameter");
        ps.setString(i, parameter);
    }

    @Override
    public String getResult(ResultSet rs, String columnName) throws SQLException {
        System.out.println("MyStringTypeHandler#getResult 1");
        return rs.getString(columnName);
    }

    @Override
    public String getResult(ResultSet rs, int columnIndex) throws SQLException {
        System.out.println("MyStringTypeHandler#getResult 2");
        return rs.getString(columnIndex);
    }

    @Override
    public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
        System.out.println("MyStringTypeHandler#getResult 3");
        return cs.getString(columnIndex);
    }
}
启用自定义的typeHander
  • 可以在mybatis-config.xml里面配置,可以选择配置一个类或者一个包。
  • 在Mapper.xml的<resultMap>直接指定typeHandler。
  • 在Mapper.xml的参数中指定typeHandler。
    <!-- 1. 在mybatis-config.xml中配置 -->
    <typeHandlers>
        <typeHandler handler="com.ankeetc.spring.type.MyStringTypeHandler"/>
    </typeHandlers>
    <!-- 2. 在Mapper.xml中resultMap元素中配置-->
    <resultMap id="BaseResultMap" type="com.ankeetc.spring.domain.UserDomain">
        <result column="name" property="name" javaType="java.lang.String" jdbcType="VARCHAR" typeHandler="com.ankeetc.spring.type.MyStringTypeHandler"/>
    </resultMap>
    <!-- 注意必须使用上面的resultMap -->
    <select id="select" resultMap="BaseResultMap" parameterType="java.lang.Long">
        SELECT * FROM tb_name WHERE id = #{id}
    </select>
    <!-- 3. 在Mapper.xml参数中配置-->
    <insert id="insert" parameterType="com.ankeetc.spring.domain.UserDomain">
        INSERT INTO tb_name (name) VALUES (#{name, jdbcType=VARCHAR, javaType=String, typeHandler=com.ankeetc.spring.type.MyStringTypeHandler})
    </insert>

5.3 枚举类型typeHandler

MyBatis中枚举类型的typeHandler则有自己特殊的规则,MyBatis内部提供了两个转化枚举类型的typeHandler给我们使用。

  • org.apache.ibatis.type.EnumTypeHandler:使用枚举字符串名称作为参数传递的
  • org.apache.ibatis.type.EnumOrdinalTypeHandler:使用整数下标作为参数传递的

6 objectFactory对象工厂

当MyBatis在构建一个结果返回的时候,都会使用ObjectFactory(对象工厂)去构建POJO,我们可以定制自己的对象工厂。MyBatis中默认的ObjectFactory是由org.apache.ibatis.reflection.factory.DefaultObjectFactory来提供服务的。

自定义objectFactory
  1. 实现ObjectFactory接口,也可以通过继承DefaultObjectFactory扩展功能。
  2. 在mybatis-config.xml中使用<objectFactory>元素。

7 environments环境变量

配置环境可以注册多个环境,每一个环境分为两大部分:一个是数据库源(dataSource)的配置,另外一个是数据库事务(transactionManager)的配置。

7.1 概述

    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
            </dataSource>
        </environment>
    </environments>
  1. default:表示默认使用哪个数据源
  2. id:表示数据源的名称
  3. transactionManager的事务类型type一共有三种:JDBC,采用JDBC方式管理事务,独立编码中我们常常使用;MANAGED,采用容器方式管理事务,在JNDI数据源中常用;自定义,由使用者自定义数据库事务管理办法,适用于特殊应用。
  4. property元素配置数据源的各类属性
  5. dataSource的type属性是提供我们对数据厍连接方式的配置:UNPOOLED(非连接池数据库)、POOLED(连接池数据库)、JNDI(JNDI数据源)、自定义数据源。

7.2 数据库事务

数据库事务是交由SqlSession去控制的,我们可以通过SqlSession提交或者回滚。在大部分的工作环境下,我们都会使用 Spring框架来控制它。

7.3 数据源

MyBatis内部为我们提供了3种数据源的实现方式:

  • UNPOOLED,使用org.apache.ibatis.datasource.unpooled.UnpooledDataSource实现。
  • POOLED,使用org.apache.ibatis.datasource.pooled.PooledDataSource实现。
  • JNDI,使用org.apache.ibatis.datasource.jndi.JndiDataSourceFactory实现。

7.4 自定义数据源

使用自定义数据源,它必须实现org.apache.ibatis.datasource.DataSourceFactory接口。然后在<dataSource>中type属性指定对应的全限定类名。

public class MyDataSourceFactory implements DataSourceFactory {

    DataSource dataSource;

    public MyDataSourceFactory() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/test");
        druidDataSource.setUsername("root");
        dataSource = druidDataSource;
    }

    private Properties properties;

    @Override
    public void setProperties(Properties props) {
        this.properties = props;
    }

    @Override
    public DataSource getDataSource() {
        return dataSource;
    }
}
    <dataSource type="com.ankeetc.spring.config.MyDataSourceFactory"/>

8 databaseIdProvider数据库厂商标识

在相同数据库厂商的环境下,数据库厂商标识没有什么意义,在实际的应用中使用得比较少,因为使用不同厂商数据库的系统还是比较少的。 MyBatis可能会运行在不同厂商的数据库中,它为此提供一个数据库标识,作用在于指定SQL到对应的数据库厂商提供的数据库中运行。

8.1 系统默认规则

系统默认规则

type="DB VENDOR"是启动MyBatis内部注册的策略器。首先 MyBatis会将你的配置读入Configuration类里面,在连接数据库后调用getDatabaseProductName()方法去获取数据库的信息,然后用我们配置的name值去做匹配来得到DatabaseId。

获得数据库的Id

可以用下面的代码来获得数据库的Id:sqlSessionFactory. getConfiguration(). getDatabaseId()

指定数据库厂商

可以指定SQL在哪个数据库厂商执行,需要在Mapper.XML中通过指定。

    <insert id="insert" parameterType="com.ankeetc.spring.domain.UserDomain" databaseId="mysql">
        INSERT INTO tb_name (name) VALUES (#{name, typeHandler=com.ankeetc.spring.type.MyStringTypeHandler})
    </insert>

8.2 自定义规则

  1. 实现org.apache.ibatis.mapping.DatabaseIdProvider接口
  2. 配置<databaseIdProvider>标签。
public class MyDatabaseIdProvider implements DatabaseIdProvider {
    private Properties properties;

    @Override
    public void setProperties(Properties p) {
        this.properties = p;
    }

    @Override
    public String getDatabaseId(DataSource dataSource) throws SQLException {
        String dbName = dataSource.getConnection().getMetaData().getDatabaseProductName();
        return this.properties.getProperty(dbName);
    }
}
    <databaseIdProvider type="MyDatabaseIdProvider">
        <property name="SQL Server" value="sqlserver"/>
        <property name="MySQL" value="mysql"/>
        <property name="DB2" value="db2"/>
        <property name="Oracle" value="oracle"/>
    </databaseIdProvider>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,422评论 0 4
  • MyBatis配置xml层次结构,而且必须注意其顺序。 MyBatis官网中文XML映射配置文件 1.proper...
    落叶飞逝的恋阅读 2,331评论 0 4
  • 1 Mybatis入门 1.1 单独使用jdbc编程问题总结 1.1.1 jdbc程序 上边使...
    哇哈哈E阅读 3,287评论 0 38
  • 那是一个冬天,车里抽着闷烟, 守了半宿工地,偶遇搞笑老汉。 文/贺立辉 这是我在一线时候的一个事儿,现在想起来仍颇...
    城管原创文学阅读 265评论 0 0
  • 今天认识个新朋友,就像世上的另一个自己。好高兴。感觉永远有说不完的话题,感觉什么都很合得来,都恰到好处。一切安排都...
    陈北北呐阅读 417评论 2 6