Mybatis - 核心配置文件Mybatis-config.xml标签详解(下)

前言

Mybatis-config.xml是Mybatis的核心配置文件,需要仔细琢磨

前面介绍了约束、properties、settings、typeAliases、typeHandlers

继续学习
在这里插入图片描述

一切以官网为准,作补充、扩展


对象工厂(objectFactory)

每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作


默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。 如果想覆盖对象工厂的默认行为,可以通过创建自己的对象工厂来实现

什么意思呢?

我们前面配置了mapper.xml的结果集类型resultType
当sql语句返回执行结果时,映射到 resultType 或其他处理结果集的参数配置对应的 Java 类型,objectFactory 对象工厂就是用来创建实体对象的类

<select id="getUserList" resultType="User">
        select * from mybatis.user
</select>

前面resultType返回的是User实体类对象,测试类List<User> userList = mapper.getUserList();直接就获得了对象,那么对象到底是谁创建的?

就是这个ObjectFactory

默认调用目标类的无参构造方法创建,也可以通过存在的参数映射来调用带有参数的构造方法

默认的ObjectFactory是DefaultObjectFactory 类,有兴趣可以查看源码,从中大致可以知道结果集映射为实体类对象的流程:

  • create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs):这个方法中传了三个参数,分别是返回的结果集类型、此类构造函数参数类型、此类构造函数参数值 的集合。从它的内部实现来看,首先调用了下面的resolveInterface方法获取返回类型,其次调用instantiateClass方法实例化出我们所需的结果集对应的实体类对象
  • instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs):此方法是用来实例化一个类(也就是对应的实体类),需要实例化的类型是通过下面的resolveInterface方法决定,从内部实现来看,这个实例化过程是通过反射实现的
  • resolveInterface(Class<?> type):此方法是用来对结果集类型进行处理,即如果我们定义一个resultType为集合类型,那么它就会根据这个类型决定出即将创建的结果集类型
  • isCollection(Class<T> type):这个方法是用来判断我们配置的类型是不是一个集合。比如如果返回多条数据,但是我们配置resultType是个普通类,那么在执行过程中就会报错
  • setProperties(Properties properties):这个方法是用来设置一些配置信息,即objectFactory中的property子元素标签内的数据,就是通过这个方法进行配置的

如何自定义

可以实现ObjectFactory接口 或者 继承 DefaultObjectFactory 来创建自己的对象工厂,改写相关的4个方法

package com.learn.util;

import org.apache.ibatis.reflection.factory.ObjectFactory;

import java.util.List;
import java.util.Properties;

public class MyObjectFactory implements ObjectFactory {
    @Override
    public <T> T create(Class<T> type) {
        return null;
    }

    @Override
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        return null;
    }

    @Override
    public <T> boolean isCollection(Class<T> type) {
        return false;
    }

    @Override
    public void setProperties(Properties properties) {

    }
}

然后在mybatis-config.xml中添加配置:

<objectFactory type="com.learn.util.MyObjectFactory">
    <property name="" value=""/>
</objectFactory>

子标签 property 中的属性会在加载全局配置文件 mybatis-config.xml 时通过 setProperties 方法被初始化到 MyObjectFactory 中,作为该类的全局参数使用

可以知道加载流程:

当 Resource 资源类加载 mybatis-config.xml 文件,并创建出 SqlSessionFactory 时,会加载配置文件中 objectFactory(默认或者自定义),并设置配置标签中的 property 参数


插件(plugins)

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用

MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback,
    getTransaction, close, isClosed):执行器拦截,sql执行的核心,可以处理很多行为,包括commit、rollback、close等等
  • ParameterHandler (getParameterObject, setParameters):参数处理器,可以获取参数、设置参数
  • ResultSetHandler (handleResultSets, handleOutputParameters):结果集处理器,可以将结果集转换List等等
  • StatementHandler (prepare, parameterize, batch, update, query):sql语句处理器,可以处理预编译状态的接口

这是一种AOP切面思想,在映射语句执行过程中,横切在某处,定义一些方法
插件使用的场景有:日志记录、权限控制、缓存控制等

如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为在试图修改或重写已有方法的行为时,很可能会破坏MyBatis 的核心模块。 这些都是更底层的类和方法,所以使用插件的时候要特别当心

具体使用:继承Interceptor接口,并指定了想要拦截的方法签名,重写方法

在这里插入图片描述

package com.learn.util;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;

import java.util.Properties;

@Intercepts({@Signature(
        type= Executor.class,
        method = "update",
        args = {MappedStatement.class,Object.class})})
public class MyInterceptor implements Interceptor {

    private Properties properties = new Properties();
    
    public Object intercept(Invocation invocation) throws Throwable {
        // implement pre processing if need
        Object returnObject = invocation.proceed();
        // implement post processing if need
        return returnObject;
    }
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

然后在核心配置文件:

<plugins>
   <plugin interceptor="com.learn.util.MyInterceptor">
       <property name="someProperty" value="100"/>
   </plugin>
</plugins>

这个插件就会拦截在Executor 实例中所有的 “update” 方法调用,
Executor 是负责执行底层映射语句的内部对象(具体的执行器)

除了用插件,还可以通过完全覆盖配置类来达到目的,继承配置类后覆盖其中的某个方法,再把它传递到SqlSessionFactoryBuilder.build(myConfig) 方法即可

总之,不懂Mybatis的源码别动这几个方法


环境配置(environments)

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中

前面我们是直接在环境中写死了

   <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

可以通过前面的properties引入外部配置文件,然后在这里修改,得到配置文件中的属性:

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

注意,这些属性名需要与外部配置文件中的name对应
在这里插入图片描述

每个 SqlSessionFactory 实例只能选择一种环境(每个数据库对应一个 SqlSessionFactory 实例,这是Mybatis的工作流程)

当然,这个环境配置还有一些属性需要注意

默认使用环境

默认使用的环境 ID(比如:default=“development”),environments标签通过default选择想要的环境
在这里插入图片描述


事务管理器(transactionManager)

Mybatis只有两种事务管理

  • JDBC :使用 JdbcTransactionFactory 生成的 JdbcTransaction 对象实现。它是以 JDBC 的方式对数据库的提交和回滚进行操作。
  • MANAGED :使用 ManagedTransactionFactory 生成的 ManagedTransactio 对象实现。它的提交和回滚方法不用任何操作,而是把事务交给WEB容器处理(JBOSS,Weblogic)。在默认情况下,它会关闭连接
  • 当然,实现 Transaction 接口也可以自定义(但是事务管理是很复杂的,自定义很难实现)

设置成MANAGED ,Mybatis就不管理事务了,即使我们update提交,数据库也不会有反应

Transaction的两个实现类:
在这里插入图片描述

基本上都是选择JDBC


数据源(dataSource)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")

数据源就是实现了 DataSource 接口的数据库连接对象
在内部配置好连接数据库需要的属性

  • UNPOOLED:非数据库连接池的管理方式,每次请求都会打开一个新的数据库连接
  • POOLED:数据库连接池,使用完连接后该连接在连接池等待
  • JNDI:为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用
  • 当然,也支持自定义的数据库连接池,implements DataSourceFactory,实现DataSourceFactory和对应的DataSource,然后将DataSourceFactory路径写到type里即可

这3个的配置都在相应的类中(工厂方法:具体实现是对应的DataSource)
在这里插入图片描述

数据库连接池类似与线程池,常用的是POOLED

关于type="[UNPOOLED|POOLED|JNDI]",可以设置一些属性,具体看官网的说明

Mybatis是支持修改属性的,通过property子标签修改
在这里插入图片描述

可以看出,环境标签是这样的:

<environments default="development">

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

environments - 》 environment -》 transactionManager 和 dataSource

这是定义Mybatis与数据库的连接,可以选择环境、选择事务管理器、事务处理器、数据源、数据库连接池

不是大佬就别想着自定义了,关于数据库、‘池’技术,太复杂了


数据库厂商标识(databaseIdProvider)

MyBatis 可以根据不同的数据库厂商执行不同的语句

因为,不同的数据库的语句会有一些不同,根据需要可以通过这个配置来设置多种数据库

多厂商的支持是基于映射语句中的 databaseId 属性

在核心配置文件中加上(这里的name是别名,真正的名字是很长一串的):

<databaseIdProvider type="DB_VENDOR">
    <property name="MySQL" value="mysql" />
    <property name="Oracle" value="oracle" />
</databaseIdProvider>

在mapper.xml就可以根据需要选择不同的数据库(mybatis会识别databaseId)

<select id="getUser" resultType="User" databaseId="mysql">
        SELECT * FROM user
</select>

具体的操作有点复杂,有空在深入

可以看MyBatis之databaseIdProvider多数据库支持


映射器(mappers)

在前面的使用中已经用过了

在这里插入图片描述

具体的mapper.xml必须注册到mybatis,mybatis才能处理

有3种注册方法:

类路径的资源引用mapper resource

也就是上面的使用

映射器使用类名扫描

如果使用使用映射器接口实现类的完全限定类名

<mappers>
        <mapper class="com.learn.dao.UserMapper"/>
</mappers>

就需要接口和xml文件放在一起且名字相同
在这里插入图片描述

才能使用
在这里插入图片描述

如果放在不同的位置

在这里插入图片描述

就无法设置:
如果是class设置的是Mapper包<mapper class="com.learn.dao.Mapper.UserMapper"/>

 Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.ClassNotFoundException: Cannot find class: com.learn.dao.Mapper.UserMapper

在这里插入图片描述

如果找的是接口:<mapper class="com.learn.dao.UserMapper"/>

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.learn.dao.UserMapper.getUserById

在这里插入图片描述

映射器使用包扫描

<package name="com.learn.dao"/>

在这里插入图片描述

可以把dao下的xml配置都扫描到

在这里插入图片描述

但是,接口和xml配置名要相同,且必须在同一包下,和类名扫描一样

在这里插入图片描述

一改名字,就会报错

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.learn.dao.UserMapper.getUserById

在这里插入图片描述

看喜好选择哪个都可以,如果想偷懒用包扫描,简单,如果想要把mapper.xml单独拿开可以选择资源引用


总结

所有的核心标签大概了解了一遍,很多需要实际查找并且关联到的很多Mybatis的知识
如:sqlsession等工作流程、日志工厂、不同数据库等后续会深入了解

其实,所有的Mybatis标签都对应着一系列的Java类,是通过解析XML文件配置,读取到Java类中的,所以,如果想深入,可以看看对应标签的类的源码

学海无涯苦作舟

都看到这了,点个赞呗(^_−)☆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值