• Mybatis配置文件——全配置解析


    我把总结放在开头,方便大家使用

    为了让大家方便的使用,特意把总结放在文章开头,有帮助到你就点个关注呗

    配置名称配置含义配置简介
    configuration包裹所有配置标签整个配置文件的顶级标签
    properties属性该标签可以引入外部配置的属性,也可以自己配置。该配置标签所在的同一个配置文件的其他配置均可以引用此配置中的属性
    setting全局配置参数用来配置一些改变运行时行为的信息,例如是否使用缓存机制,是否使用延迟加载,是否使用错误处理机制等。 此项数据过于庞大,在下面细讲
    typeAliases类型别名用来设置一些别名来代替Java的长类型声明(如 java.lang.int变为int),减少配置编码的冗余
    typeHandlers类型处理器将数据库获取的值以合适的方式转换为Java 类型,或者将Java类型的参数转换为数据库对应的类型
    objectFactory对象工厂实例化目标类的工厂类配置
    plugins插件可以通过插件修改MyBatis的核心行为,例如对语句执行的某一点进行拦截调用
    environments环境集合属性对象数据库环境信息的集合。在一个配置文件中,可以有多种数据库环境集合,这样可以使MyBatis将SQL同时映射至多个数据库
    environment环境子属性对象数据库环境配置的详细配置
    transactionManager事务管理指定MyBat is的事务管理器
    dataSource数据源使用其中的type指定数据源的连接类型,在标签对中可以使用

    configuration

    configuration是整个配置文件的根标签,实际上也对应着MyBatis里面最重要的配置类Configuration。
    它贯穿MyBatis执行流程的每一个环节。我们打开这个类看一下,这里面有很多的属性,跟其他的子标签也能对应上。

    properties

    第一个一级标签是properties,用来配置参数信息,比如最常见的数据库连接信息。

    为了避免直接把参数写死在xml配置文件中,我们可以把这些参数单独放在properties文件中,用properties标签引入进来,然后在xml 配置文件中用$引用就可以了。
    可以用resource引用应用里面的相对路径,也可以用url指定本地服务器或者网络的绝对路径。

    settings

    setttings里面是MyBatis的一些核心配置,在 MyBatis 中 settings 是最复杂的配置,它能深刻影响 MyBatis 底层的运行,但是在大部分情况下使用默认值便可以运行,所以在大部分情况下不需要大量配置它,只需要修改一些常用的规则即可,比如自动映射、驼峰命名映射、级联规则、是否启动缓存、执行器(Executor)类型等。

    属性名作用有效值默认值
    cacheEnabled该配置影响所有映射器中配置缓存的全局开关true,falsetrue
    lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。在特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态true,falsefalse
    aggressiveLazyLoading当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载true,felse版本3.4.1 (不包含)之前 true,之后 false
    multipleResultSetsEnabled是否允许单一语句返回多结果集(需要兼容驱动)true,felsetrue
    useColumnLabel使用列标签代替列名。不同的驱动会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果true,felsetrue
    useGeneratedKeys允许JDBC 支持自动生成主键,需要驱动兼容。如果设置为 true,则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)true,felsefalse
    autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射。 PARTIAL 表示只会自动映射,没有定义嵌套结果集和映射结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)NONE、PARTIAL、FULLPARTIAL
    autoMappingUnknownColumnBehavior指定自动映射当中未知列(或未知属性类型)时的行为。 默认是不处理,只有当日志级别达到 WARN 级别或者以下,才会显示相关日志,如果处理失败会抛出 SqlSessionException 异常NONE、WARNING、FAILINGNONE
    defaultExecutorType配置默认的执行器。SIMPLE 是普通的执行器;REUSE 会重用预处理语句(prepared statements);BATCH 执行器将重用语句并执行批量更新SIMPLE、REUSE、BATCHSIMPLE
    defaultStatementTimeout设置超时时间,它决定驱动等待数据库响应的秒数任何正整数Not Set (null)
    defaultFetchSize设置数据库驱动程序默认返回的条数限制,此参数可以重新设置任何正整数Not Set (null)
    safeRowBoundsEnabled允许在嵌套语句中使用分页(RowBounds)。如果允许,设置 falsetrue,felsefalse
    safeResultHandlerEnabled允许在嵌套语句中使用分页(ResultHandler)。如果允许,设置falsetrue,felsefalse
    mapUnderscoreToCamelCase是否开启自动驼峰命名规则映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射true,felsefalse
    localCacheScopeMyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速联复嵌套査询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlScssion 的不同调用将不会共享数据SESSION,STATEMENTSESSION
    jdbcTypeForNull当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHERNULL、VARCHAR、OTHEROTHER
    lazyLoadTriggerMethods指定哪个对象的方法触发一次延迟加载equals、clone、hashCode、toString
    defaultScriptingLanguage指定动态 SQL 生成的默认语言org.apache.ibatis .script.ing.xmltags .XMLDynamicLanguageDriver
    callSettersOnNulls指定当结果集中值为 null 时,是否调用映射对象的 setter(map 对象时为 put)方法,这对于 Map.kcySet() 依赖或 null 值初始化时是有用的。注意,基本类型(int、boolean 等)不能设置成 nulltrue,felsefalse
    logPrefix指定 MyBatis 增加到日志名称的前缀任何字符串Not set
    loglmpl指定 MyBatis 所用日志的具体实现,未指定时将自动査找SLF4J,LOG4J,LOG4J2,JDK_LOGGING,COMMONS_LOGGING,ST DOUT_LOGGING,NO_LOGGINGNot set
    proxyFactory指定 MyBatis 创建具有延迟加栽能力的对象所用到的代理工具CGLIB,JAVASSISTJAVASSIST (MyBatis 版本为 3.3 及以上的)
    vfslmpl指定 VFS 的实现类提供 VFS 类的全限定名,如果存在多个,可以使用逗号分隔Not set
    useActualParamName允许用方法参数中声明的实际名称引用参数。要使用此功能,项目必须被编译为 Java 8 参数的选择。(从版本 3.4.1 开始可以使用)true,felsetrue

    settings 的配置项很多,但是真正用到的不会太多,我们把常用的配置项研究清楚就可以了,比如关于缓存的 cacheEnabled,关于级联的 lazyLoadingEnabled 和 aggressiveLazy Loading,关于自动映射的 autoMappingBehavior 和 mapUnderscoreToCamelCase,关于执行器类型的 defaultExecutorType 等。

    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    typeAliases

    TypeAlias是类型的别名,跟Linux系统里面的alias一样,主要用来简化类名全路径的拼写。比如我们的参数类型和返回值类型都可能会用到我们的Bean,如果每个地方都配置全路径的话,那么内容就比较多,还可能会写错。
    我们可以为自己的Bean 创建别名,既可以指定单个类,也可以指定一个package,自动转换。

    <typeAliases>
    	<typeAlias alias="blog" type="com.domain.Blog" />
    </typeAliases>
    
    • 1
    • 2
    • 3

    配置了别名以后,在配置文件中只需要写别名就可以了,比如com.domain.Blog 可以简化成 blog。

    <select id="selectBlogByBean" parameterType="blog" resultType="blog" 
    	select bid, name, author_id authorld from blog where name = 'S{name}'
    </select>
    
    
    • 1
    • 2
    • 3
    • 4

    MyBatis里面有很多系统预先定义好的类型别名,在TypeAliasRegistry 中。所以可以用string 代替java.lang.String。

    typeHandlers

    由于Java类型和数据库的JDBC类型不是一一对应的(比如String与varchar、char.text),所以我们把Java对象转换为数据库的值,和把数据库的值转换成Java对象,需要经过一定的转换,这两个方向的转换就要用到TypeHandler。
    当参数类型和返回值是一个对象的时候,我没有做任何的配置,为什么对象里面的一个String属性,可以转换成数据库里面的varchar字段?
    这是因为MyBatis 已经内置了很多TypeHandler(在type包下),它们全部全部注册在TypeHandlerRegistry中,他们都继承了抽象类BaseTypeHandler,泛型就是要处理的Java数据类型。
    这个也是为什么大部分类型都不需要处理。当我们查询数据和登记数据,做数据类型转换的时候,就会自动调用对应的TypeHandler的方法。
    在这里插入图片描述
    如果我们需要自定义一些类型转换规则,或者要在处理类型的时候做一些特殊的动作,就可以编写自己的TypeHandler,跟系统自定义的TypeHandler一样,继承抽象类BaseTypeHandler。有4个抽象方法必须实现,我们把它分成两类:
    set方法是从Java类型转换成JDBC类型的
    get方法是从JDBC类型转换成Java类型的

    从Java类型到JDBC类型从JDBC类型到Java类型
    setNonNullParameter:设置非空参数getNullableResult:获取空结果集(根据列名),一般都是调用这个
    .getNullableResult:获取空结果集(根据下标值)
    .getNullableResult:存储过程用的

    举个例子:

    一个商户,在登记的时候需要注册它的经营范围。比如1手机,2电脑,3相机,4平板,在界面上是一个复选框(checkbox)。
    在数据库保存的是用逗号分隔的字符串,例如“1,3,4”,而返回给程序的时候是整形数组{1,3,4}。
    在每次获取数据的时候转换?还是在bean的get方法里面转换?似乎都不太合适。这时候我们可以写一个Integer[]类型的TypeHandler。
    第一步:写TypeHandler

    public class MyTypeHandler extends BaseTypeHandler<String> {
        public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
                throws SQLException {
            // 设置 String 类型的参数的时候调用,Java类型到JDBC类型
            // 注意只有在字段上添加typeHandler属性才会生效
            // insertBlog name字段
            System.out.println("---------------setNonNullParameter1:"+parameter);
            ps.setString(i, parameter);
        }
    
        public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
            // 根据列名获取 String 类型的参数的时候调用,JDBC类型到java类型
            // 注意只有在字段上添加typeHandler属性才会生效
            System.out.println("---------------getNullableResult1:"+columnName);
            return rs.getString(columnName);
        }
    
        public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
            // 根据下标获取 String 类型的参数的时候调用
            System.out.println("---------------getNullableResult2:"+columnIndex);
            return rs.getString(columnIndex);
        }
    
        public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
            System.out.println("---------------getNullableResult3:");
            return cs.getString(columnIndex);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    第二步,在mybatis-config.xml文件中注册:

    <typeHandlers>
    	<typeHandler handler="com.type.MyTypeHandler"></typeHandler>
    </typeHandlers>-->
    
    • 1
    • 2
    • 3

    第三步,在我们需要使用的字段上指定,比如:
    插入值的时候,从Java类型到JDBC类型,在字段属性中指定typehandler:

        <insert id="insertBlog" parameterType="blog">
        insert into blog
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="bid != null">
                    bid,
                </if>
                <if test="name != null">
                    name,
                </if>
                <if test="authorId != null">
                    author_id,
                </if>
            </trim>
            <trim prefix="values (" suffix=")" suffixOverrides=",">
                <if test="bid != null">
                    #{bid,jdbcType=INTEGER},
                </if>
                <if test="name != null">
                    #{name,jdbcType=VARCHAR,typeHandler=com.gupaoedu.type.MyTypeHandler},
                </if>
                <if test="authorId != null">
                    #{authorId,jdbcType=INTEGER},
                </if>
            </trim>
        </insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    返回值的时候,从JDBC类型到Java类型,在resultMap 的列上指定typehandler:

    <result column="name" property="name" jdbcType="VARCHAR" typeHandler="com.type.MyTypeHandler"/>
    
    
    • 1
    • 2

    objectFactory

    当我们把数据库返回的结果集转换为实体类的时候,需要创建对象的实例,由于我们不知道需要处理的类型是什么,有哪些属性,所以不能用new的方式去创建。只能通过反射来创建。
    在MyBatis里面,它提供了一个工厂类的接口,叫做ObjectFactory,专门用来创建对象的实例(MyBatis封装之后,简化了对象的创建),里面定义了4个方法。
    在这里插入图片描述
    作用
    设置参数时调用
    创建对象(调用无参构造函数)
    创建对象(调用带参数构造函数)
    判断是否集合

    ObjectFactory有一个默认的实现类DefaultObjectFactory。创建对象的方法最终都调用了instantiateClass(),这里面能看到反射的代码。

    默认情况下,所有的对象都是由DefaultObjectFactory 创建。

    我们可以直接用自定义的工厂类来创建对象:

    public class ObjectFactoryTest {
        public static void main(String[] args) {
            GPObjectFactory factory = new GPObjectFactory();
            Blog myBlog = (Blog) factory.create(Blog.class);
            System.out.println(myBlog);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果想要修改对象工厂在初始化实体类的时候的行为,就可以通过创建自己的对象工厂,继承DefaultObjectFactory来实现(不再需要实现ObjectFactory接口)。
    例如:

    public class ObjectFactory extends DefaultObjectFactory {
        @Override
        public Object create(Class type) {
            System.out.println("创建对象方法:" + type);
            if (type.equals(Blog.class)) {
                Blog blog = (Blog) super.create(type);
                blog.setName("object factory");
                blog.setBid(1111);
                blog.setAuthorId(2222);
                return blog;
            }
            Object result = super.create(type);
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这样我们就直接拿到了一个对象。
    如果在config文件里面注册,在创建对象的时候会被自动调用:

    <objectFactory type="org.mybatis.example.ObjectFactory"
    <!--对象工厂注入的参数-->
    <property name="666" value="666"/>
    </objectFactory>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样,就可以让 MyBatis的创建实体类的时候使用我们自己的对象工厂。
    附:
    1、什么时候调用了objectFactory.create()?
    创建 DefaultResultSetHandler的时候,和创建对象的时候。
    2、创建对象后,已有的属性为什么被覆盖了?
    在DefaultResultSetHandler类的395行getRowValue()方法里面里面调用了applyPropertyMappings)。
    3、返回结果的时候,ObjectFactory和TypeHandler哪个先工作?
    肯定是先创建对象,所以先是ObjectFactory,再是TypeHandler。

    plugins

    插件是 MyBatis的一个很强大的机制。跟很多其他的框架一样,MyBatis 预留了插件的接口,让 MyBatis更容易扩展。
    在这里插入图片描述

    environments environment

    environments标签用来管理数据库的环境,比如我们可以有开发环境、测试环境、生产环境的数据库。可以在不同的环境中使用不同的数据库地址或者类型。

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true
    jdbc.username=root
    jdbc.password=123456
    
    • 1
    • 2
    • 3
    • 4
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/><!-- 单独使用时配置成MANAGED没有事务 -->
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    一个environment标签就是一个数据源,代表一个数据库。这里面有两个关键的标签,一个是事务管理器,一个是数据源。

    transactionManager

    如果配置的是JDBC,则会使用Connection对象的commit()、rollback()、close()管理事务。

    如果配置成MANAGED,会把事务交给容器来管理,比如JBOSS,Weblogic。因为我们跑的是本地程序,如果配置成MANAGE不会有任何事务。

    如果是Spring + MyBatis,则没有必要配置,因为我们会直接在applicationContext.xml里面配置数据源和事务,覆盖MyBatis的配置。

    dataSource

    数据源,顾名思义,就是数据的来源,一个数据源就对应一个数据库。在Java里面,它是对数据库连接的一个抽象。
    一般的数据源都会包括连接池管理的功能,所以很多时候也把 DataSource直接称为连接池,准确的说法应该是:带连接池功能的数据源。

    为什么要用连接池?

    除了连接池之外,大家应该也听过很多其他的池,比如线程池,内存池,对象池,这种池化技术达到的目的基本上一样的。

    如果没有连接池,那么每一个用户、每一次会话连接数据库都需要直接创建和释放连接,这个过程是会消耗的一定的时间的,并且会消耗应用和服务器的性能。

    当我们没有使用连接池的时候,客户程序得到的连接是一个物理连接,我们调用close()方法会把这个连接真正地关闭。

    如果采用连接池技术,在应用程序里面关闭连接的时候,物理连接没有被真正关闭掉,只是回到了连接池里面。

    从这个角度来考虑,一般的连接池都会有初始连接数、最大连接数、回收时间等等这些参数,提供提前创建/资源重用/数量控制/超时管理等等这些功能。

    MyBatis自带了两种数据源,UNPOOLED和POOLED。也可以配置成其他数据库,比如C3P0、Hikari等等。市面上流行的数据源,一般都有连接池功能。

    在跟Spring集成的时候,事务和数据源都会交给Spring来管理,不再使用MyBatis配置的数据源。

  • 相关阅读:
    java学习--day24(单例模式&序列化&Lambda表达式)
    AI Earth ——开发者模式案例4:浙江省森林区域植被生长分析
    洛谷P2196 [NOIP1996 提高组] 挖地雷【动态规划思路分析】看完直接举一反三!
    VS code创建Vue项目 方法1:create+项目
    直方图投影法判断裂缝走势(裂缝类型)
    前端工程化之小白眼中的前端开发 vs 实际的前端开发
    超全整理,服务端性能测试-tomcat部署项目/查看日志(细致)
    JAVA 0基础 基本数据类型之间的互相转换
    excel表格乱码怎么解决呢?
    C++17:variant
  • 原文地址:https://blog.csdn.net/weixin_44688973/article/details/125891522