Mybatis-config.xml是Mybatis的核心配置文件,需要仔细琢磨
前面介绍了约束、properties、settings、typeAliases、typeHandlers
一切以官网为准,作补充、扩展
每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作
默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。 如果想覆盖对象工厂的默认行为,可以通过创建自己的对象工厂来实现
什么意思呢?
我们前面配置了mapper.xml的结果集类型resultType
当sql语句返回执行结果时,映射到 resultType 或其他处理结果集的参数配置对应的 Java 类型,objectFactory 对象工厂就是用来创建实体对象的类
<select id="getUserList" resultType="User">
select * from mybatis.user
</select>
前面resultType返回的是User实体类对象,测试类List
直接就获得了对象,那么对象到底是谁创建的?
就是这个ObjectFactory
默认调用目标类的无参构造方法创建,也可以通过存在的参数映射来调用带有参数的构造方法
默认的ObjectFactory是DefaultObjectFactory 类,有兴趣可以查看源码,从中大致可以知道结果集映射为实体类对象的流程:
create(Class type, List> constructorArgTypes, List
:这个方法中传了三个参数,分别是返回的结果集类型、此类构造函数参数类型、此类构造函数参数值 的集合。从它的内部实现来看,首先调用了下面的resolveInterface方法获取返回类型,其次调用instantiateClass方法实例化出我们所需的结果集对应的实体类对象instantiateClass(Class type, List> constructorArgTypes, List
:此方法是用来实例化一个类(也就是对应的实体类),需要实例化的类型是通过下面的resolveInterface方法决定,从内部实现来看,这个实例化过程是通过反射实现的resolveInterface(Class> type)
:此方法是用来对结果集类型进行处理,即如果我们定义一个resultType为集合类型,那么它就会根据这个类型决定出即将创建的结果集类型isCollection(Class 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 参数
MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用
MyBatis 允许使用插件来拦截的方法调用包括:
这是一种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的源码别动这几个方法
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&useUnicode=true&characterEncoding=UTF8&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>
每个 SqlSessionFactory 实例只能选择一种环境(每个数据库对应一个 SqlSessionFactory 实例,这是Mybatis的工作流程)
当然,这个环境配置还有一些属性需要注意
默认使用环境
默认使用的环境 ID(比如:default=“development”),environments标签通过default选择想要的环境
Mybatis只有两种事务管理
设置成MANAGED ,Mybatis就不管理事务了,即使我们update提交,数据库也不会有反应
基本上都是选择JDBC
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")
数据源就是实现了 DataSource 接口的数据库连接对象
在内部配置好连接数据库需要的属性
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与数据库的连接,可以选择环境、选择事务管理器、事务处理器、数据源、数据库连接池
不是大佬就别想着自定义了,关于数据库、‘池’技术,太复杂了
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多数据库支持
在前面的使用中已经用过了
具体的mapper.xml必须注册到mybatis,mybatis才能处理
有3种注册方法:
也就是上面的使用
如果使用使用映射器接口实现类的完全限定类名
class="com.learn.dao.UserMapper"/>
</mappers>
如果放在不同的位置
就无法设置:
如果是class设置的是Mapper包
Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.ClassNotFoundException: Cannot find class: com.learn.dao.Mapper.UserMapper
如果找的是接口:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.learn.dao.UserMapper.getUserById
"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类中的,所以,如果想深入,可以看看对应标签的类的源码
学海无涯苦作舟
都看到这了,点个赞呗(^_−)☆