本文已参与「新人创作礼」活动,一起开启掘金创作之路。
XML配置-插件(plugins)
Mybatis实际是封装了JDBC,底层操作还是JDBC,JDBC的一套流程是:
- 获取连接
- 获取预编译对象
- 执行
- 获取结果集
同样的Mybatis在操作数据库时应该对应的有四个职能相似的API。Mybatis官网有四个如下:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
我的理解是Mybatis通过这四个API来执行一条SQL,在这个过程中我们是可以修改Mybatis的默认行为的,而修改默认行为可能会造成框架不能正常使用,因为这些都是底层的核心封装。
如果你想改变Mybatis的默认行为,可以实现Interceptor接口,并指定要拦截的方法签名, 官网给出的示例:
// ExamplePlugin.java
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin 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;
}
}
<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
通过插件的编写以及配置,该插件会拦截Executor示例中所有update方法代用,Exexcutor是执行底层迎神语句的对象,不清楚的可以看下Mybatis(一)中Mybatis架构图
小结:实际开发中,很少会去改变Mybatis默认的行为,当然除了通过插件的方式,还可以通过覆盖配置类来改变行为,具体做法是继承配置类,然后构建SqlSessionFactory时,将他传递到SqlSessionFactoryBuilder的build方法中即可
XML配置-环境配置(environments)
这里的配置指的是数据源的配置,JDBC连接数据库需要四个参数,在Mybatis中这四个参数是配置在核心配置文件中的。在配置文件中是可以配置多套数据源的,如果不指定数据源的情况下会使用默认的数据源。
上图中标签中有个default属性,当你不指定数据源时就会通过id去找到默认的数据源,需要注意的是,不指定数据源的情况下一定要保证默认的数据源id是存在的。
上图中配置了三个数据源,在创建SqlSessionFactory时,只能使用其中的一个数据源,指定的方式是SqlSessionFactoryBuilder的build重载方法,默认我们都是这么写的:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
实际我们可以使用其他的重载方法来传入自己需要的数据源:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
事务管理器
使用JDBC在进行增删改的时候都需要commit()来提交连接,rollback()来回滚,在操作PL/SQL等可视化软件时在手动增删改后,需要点击左上角的一个提交按钮,这个按钮的作用等同于commit。Mybatis对于事务的管理有两种方式:
-
JDBC:这个配置完全使用 JDBC 的提交和回滚,它依赖从数据源获得的连接来管理事务作用域。\
-
MANAGED:这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。
自定义Mybatis事物控制\
自定义Mybatis事务
- 实现TransactionFactory 类,用该类的全限定类型替换type属性的值就好了
public interface TransactionFactory {
default void setProperties(Properties props) { // 从 3.5.2 开始,该方法为默认方法
// 空实现
}
Transaction newTransaction(Connection conn);
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
- 实现Transaction 接口,在事务管理器实例化后,所有在 XML 中配置的属性将会被传递给 setProperties() 方法。
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;
}
小结:单独使用Mybatis时需要配置,使用Spring跟Mybatis的整合包时是不需要配置事务管理的。二者整合后,spring会有自带的配置类覆盖。
数据源
Mybatis在核心配置文件中配置数据源时有三种选择,配置时在标签的type属性配上不同的数据源即可。
- 一般使用的是POOLED,这是一个池化的数据源,也就是我们常说的连接池,每个数据库连接使用完毕后不是关闭,而是放回池子中。 这样减少了创建连接的时间,并发下能够快速响应。通常配置数据源时,最简单的只需要driver,url,username,password四个属性即可,其他都是Mybatis默认的设置,实际Mybatis还提供了很多数据源属性,针对POOLED数据源还有以下配置:
| defaultTransactionIsolationLevel | 默认的连接事务隔离级别 |
|---|---|
| defaultNetworkTimeout | 等待数据库操作完成的的默认超时时间 |
| poolMaximumActiveConnections | 可活动的连接数,Mybatis默认是10,如果你配置成0,那么Mybatis将不能使用 |
| poolMaximumIdleConnections | 任意时间下,可以存在的空闲连接数 |
| poolMaximumCheckoutTime | 被强制返回时,连接被检出的时间,默认是20秒 |
| poolTimeToWait | 获取连接超时,会打印日志,并重新获取一个连接 |
| poolMaximumLocalBadConnectionTolerance | 作用与每一个从池中获取数据源的线程,如果获取到坏连接,那么会重新回去连接,但是连接的数量不能超过该值与可活动连接数的和,默认值是3 |
| poolPingQuery | 发送到数据库的侦测查询,用来检验连接是否正常工作并接受请求。默认是没有开启侦测查询 |
| poolPingEnabled | 是否启动侦测查询。开启需要将poolPingQuery属性添加在一个可执行的SQL语句上(最好是非常快的SQL),默认值是false |
| poolPingConnectionsNotUsedFor | 配置poolPingQuery的频率。可以将超时时间配置的跟数据库一样,来避免不必要的侦测,默认值是0.也就是说所有连接每一时刻都被侦测,当然poolPingEnabled为true时适用。 |
- 第二个要介绍的数据源是UNPOOLED,这个数据源的每个连接都会被打开和关闭。速度比较慢,不管大项目小项目都不建议使用,专一一点,用第一种,第二种知道就好了。它的配置除了常规的几个数据源外,还有以下两个配置:
| defaultTransactionIsolationLevel | 默认的连接事务隔离级别 |
|---|---|
| defaultNetworkTimeout | 等待数据库操作完成的的默认超时时间 |
3.JNDI 这个数据源是为了能在EJB或应用服务器中使用,容器可以在外部配置输急眼,然后放在JNDI 的上下文中即可。它只需要配置两个属性即可:
| initial_context | 会在配置的属性对应的值中寻找上下文 |
|---|---|
| data_source | 引用数据源实例位置的上下文路径 |
XML配置-数据库厂商标识(databaseldProvider)
Java中有定义了一套JDBC规范,把具体的实现交给数据库厂商自己实现,例如MySQL与Oracle的一些语法及命名都不太一致。Mybatis针对这个问题使用databasedId属性来区分不同数据库厂商的语句。当Mybatis加载到两条相同的语句时,Mybatis会加载匹配当前数据库databaseId的语句。
当然Mybatis也可以支持多厂商特性,只需要在核心配置文件中配置如下代码即可。
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
自定义数据库厂商标识
// 实现ibatis包下的DatabaseidProvider即可
public interface DatabaseIdProvider {
default void setProperties(Properties p) { // 从 3.5.2 开始,该方法为默认方法
// 空实现
}
String getDatabaseId(DataSource dataSource) throws SQLException;
}
XML配置-映射器(mappers)
映射器的作用是找到对应的SQL文件,在Mybatis入门的那篇文章中介绍到,映射文件实际上就是实现类。使用JDBC写法时,实现类实现接口,通过多态来找到对应的执行方法。那么Mybatis中的映射文件和接口是通过核心配置文件来建立联系的。Mybatis为我们提供了四种方式。
<mappers>
<!-- 使用相对于类路径的资源引用 -->
<!--<mapper resource="com/evader/mapper/UserMapper.xml"></mapper>-->
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<!--<package name="com.evader.mapper"/>-->
<!-- 使用映射器接口实现类的完全限定类名 -->
<!--<mapper class="com.evader.mapper.UserMapper"></mapper>-->
<!-- 使用完全限定资源定位符(URL) -->
<mapper url="file:///D:/develop/idea/workspace/mybatis-review/mybatis-02/src/main/java/com/evader/mapper/UserMapper.xml"></mapper>
</mappers>
小结:使用包的方式配置映射器是最方便的,完全限定资源定位符的意思是xml的绝对路径,那么file:///是固定的不写是找不到的。需要注意的是引用时注意是/分割还是.分割,对于笔者最后的绝对路径,切记不可换行,不信你自己换个试试?