核心配置文件:Mybatis-config.xml

Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息

配置(configuration)

在mybatis-config.xml文件中标签都有规定的顺序,需要按照以下顺序添加

properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?

属性(properties)

我们可以通过properties来实现引用文件。Mybatis的一些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在properties元素的子元素中设置

  1. 编写一个配置文件(db.properties)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/learn?serverTimezone=GMT&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456789
  1. 在mybatis-config.xml中引入
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--核心配置文件-->
<configuration> <!--引入外部配置文件-->
<properties resource="db.properties" /> <!--也可以配置文件中写一部分,标签中写一部分-->
<!--优先使用外部配置文件中的配置-->
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="pwd" value="123456789"/>
</properties> <environments default="test"> <environment id="test">
<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> <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册-->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
  1. 测试
@Test
public void test() {
//获取SQLSession对象
SqlSession sqlSession = MybatisUtil.getSqlSession(); try { UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList(); for (User user : userList) {
System.out.println(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭SQLSession
sqlSession.close();
}
}

Mybatis会先读取properties元素体内的指定属性,再根据resource属性读取类路径下属性文件。所以外部配置文件中编写的配置会覆盖内部标签编写的配置,外部配置文件拥有更高优先级

设置(setting)

这是Mybatis中极为重要的调整设置,他们会改变Mybatis的运行时行为

更多设置请参考:https://mybatis.org/mybatis-3/zh/configuration.html#settings

环境配置(environments)

Mybatis可以配置成适应多种环境

尽管可以配置多个环境,但每个SQLSessionFactory实例只能选择一种环境

Mybatis默认的事务管理器就是JDBC,数据源是POOLED

<environments default="test">	<!--需要使用的环境-->

    <!--环境一-->
<environment id="development"> <!--id:每套environment的唯一标识-->
<transactionManager type="JDBC"/> <!--事务管理器的配置-->
<dataSource type="POOLED"> <!--数据源的配置-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/learn?serverTimezone=GMT&amp;useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456789"/>
</dataSource>
</environment> <!--环境二-->
<environment id="test">
<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>

类型别名(typeAliases)

类型别名为Java类型设置一个短的名字,它仅用于XML配置,存在的意义仅在于用来减少类完全限定名的冗余

<typeAliases>
<typeAlias alias="User" type="com.luoqing.model.User"/>
</typeAliases>

也可以指定一个包名,Mybatis会在包名下搜索需要的JavaBean

<typeAliases>
<package name="com.luoqing.model" />
</typeAliases>

每一个在包名下的JavaBean,在没有注解的情况下,会使用Bean首字母小写的非限定类名来作为它的别名

如果有注解则其别名为其注解值

//这个类的别名为user
@Alias("user")
public class User {
……
}

在实体类比较少的时候,使用第一种方式。如果实体类十分多,建议使用第二种

类型处理器(typeHandlers)

Mybatis使用typeHandlers将数据库中字段的类型转换为java类中属性的类型,或将java类中属性的类型转换为数据库中字段的类型

通过Configuration对象获取

@Test
public void myTest() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
TypeHandlerRegistry typeHandlerRegistry = sqlSession.getConfiguration().getTypeHandlerRegistry();
Collection<TypeHandler<?>> list = typeHandlerRegistry.getTypeHandlers();
System.out.println(list.size());
for (TypeHandler<?> typeHandler : list) {
System.out.println(typeHandler.getClass().getName());
} sqlSession.close(); }

执行结果如下。以下所有的处理器类位于mybatis-X.X.X.jar/org/apache/ibatis/type中

40
org.apache.ibatis.type.InstantTypeHandler
org.apache.ibatis.type.MonthTypeHandler
org.apache.ibatis.type.JapaneseDateTypeHandler
org.apache.ibatis.type.UnknownTypeHandler
org.apache.ibatis.type.DateTypeHandler
org.apache.ibatis.type.CharacterTypeHandler
org.apache.ibatis.type.BigIntegerTypeHandler
org.apache.ibatis.type.SqlxmlTypeHandler
org.apache.ibatis.type.LocalDateTimeTypeHandler
org.apache.ibatis.type.ArrayTypeHandler
org.apache.ibatis.type.YearTypeHandler
org.apache.ibatis.type.FloatTypeHandler
org.apache.ibatis.type.NStringTypeHandler
org.apache.ibatis.type.BooleanTypeHandler
org.apache.ibatis.type.ByteTypeHandler
org.apache.ibatis.type.ClobTypeHandler
org.apache.ibatis.type.BigDecimalTypeHandler
org.apache.ibatis.type.ByteArrayTypeHandler
org.apache.ibatis.type.BlobTypeHandler
org.apache.ibatis.type.DateOnlyTypeHandler
org.apache.ibatis.type.YearMonthTypeHandler
org.apache.ibatis.type.SqlDateTypeHandler
org.apache.ibatis.type.OffsetTimeTypeHandler
org.apache.ibatis.type.LongTypeHandler
org.apache.ibatis.type.TimeOnlyTypeHandler
org.apache.ibatis.type.ZonedDateTimeTypeHandler
org.apache.ibatis.type.BlobInputStreamTypeHandler
org.apache.ibatis.type.LocalDateTypeHandler
org.apache.ibatis.type.IntegerTypeHandler
org.apache.ibatis.type.StringTypeHandler
org.apache.ibatis.type.BlobByteObjectArrayTypeHandler
org.apache.ibatis.type.ShortTypeHandler
org.apache.ibatis.type.NClobTypeHandler
org.apache.ibatis.type.LocalTimeTypeHandler
org.apache.ibatis.type.ClobReaderTypeHandler
org.apache.ibatis.type.SqlTimestampTypeHandler
org.apache.ibatis.type.SqlTimeTypeHandler
org.apache.ibatis.type.ByteObjectArrayTypeHandler
org.apache.ibatis.type.OffsetDateTimeTypeHandler
org.apache.ibatis.type.DoubleTypeHandler

Mybatis已经为我们写好了40个类型处理器

其中DateTypeHandlers的源码如下

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package org.apache.ibatis.type; import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date; public class DateTypeHandler extends BaseTypeHandler<Date> {
public DateTypeHandler() {
} /**
获取到对应的java类型的对象,将其转换为jdbc类型
*/
public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
ps.setTimestamp(i, new Timestamp(parameter.getTime()));
} /**
获取到对应列的jdbc类型的对象,将其转换为java类型
*/
public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
Timestamp sqlTimestamp = rs.getTimestamp(columnName);
return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;
} /**
根据索引获取到对应的数据的jdbc类型将其转换为java类型
*/
public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
Timestamp sqlTimestamp = rs.getTimestamp(columnIndex);
return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;
} /**
这个方法用在存储过程中。将jdbc类型转换为java类型
*/
public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
Timestamp sqlTimestamp = cs.getTimestamp(columnIndex);
return sqlTimestamp != null ? new Date(sqlTimestamp.getTime()) : null;
}
}

它的父类BaseTypeHandler<T>

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package org.apache.ibatis.type; import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.executor.result.ResultMapException;
import org.apache.ibatis.session.Configuration; public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
/** @deprecated */
@Deprecated
protected Configuration configuration; public BaseTypeHandler() {
} /** @Deprecated表示此方法或者类不推荐使用,但是不代表不能用*/
/** @deprecated */
@Deprecated
public void setConfiguration(Configuration c) {
this.configuration = c;
} public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
} try {
/** jdbcType是一个枚举类型 */
/** 将对应的jdbc类型设置为null */
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException var7) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: " + var7, var7);
}
} else {
try {
this.setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception var6) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . Try setting a different JdbcType for this parameter or a different configuration property. Cause: " + var6, var6);
}
} } public T getResult(ResultSet rs, String columnName) throws SQLException {
try {
return this.getNullableResult(rs, columnName);
} catch (Exception var4) {
throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + var4, var4);
}
} public T getResult(ResultSet rs, int columnIndex) throws SQLException {
try {
return this.getNullableResult(rs, columnIndex);
} catch (Exception var4) {
throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set. Cause: " + var4, var4);
}
} public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
try {
return this.getNullableResult(cs, columnIndex);
} catch (Exception var4) {
throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement. Cause: " + var4, var4);
}
} //定义了四个抽象方法,并在上面接口方法的实现中使用了它们
//具体的实现交给子类去完成
public abstract void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException; public abstract T getNullableResult(ResultSet var1, String var2) throws SQLException; public abstract T getNullableResult(ResultSet var1, int var2) throws SQLException; public abstract T getNullableResult(CallableStatement var1, int var2) throws SQLException;
}

BaseTypeHandler是一个抽象类,也是类型处理器的基类。它作为TypeHandler接口的初步实现,实现了TypeHandler的四个方法;还另外定义了四个抽象方法,也就是DateTypeHandler中的四个方法。系统定义的40个TypeHandler方法都继承自BaseTypeHandler

实现的接口TypeHandler<T>

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package org.apache.ibatis.type; import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; public interface TypeHandler<T> {
void setParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException; T getResult(ResultSet var1, String var2) throws SQLException; T getResult(ResultSet var1, int var2) throws SQLException; T getResult(CallableStatement var1, int var2) throws SQLException;
}

如果我们要自定义typeHandler时:

  • 继承BaseTypeHandler类
  • 实现TypeHandler接口

一般不需要自定义,使用默认的就够了

映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件

方式一:

<!-- 使用相对于类路径的资源引用,在resource文件夹中 -->
<mappers>
<mapper resource="com/luoqing/dao/UserMapper.xml"/>
</mappers>

方式二:使用class文件绑定注册

<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="com.luoqing.dao.UserMapper.xml"/>
</mappers>

注意:

  • 接口和它的Mapper配置文件必须同名
  • 接口和它的Mapper配置文件必须在同一个包下

方式三:

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="com.luoqing.dao"/>
</mappers>

注意:

  • 接口和它的Mapper配置文件必须同名
  • 接口和它的Mapper配置文件必须在同一个包下

方式四:使用映射器接口实现类的完全限定名(因为基本不使用,在此不多赘述,如要学习请移步官方文档)

作用域(Scope)和生命周期

不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题

SqlSessionFactoryBuilder

一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次。因此 SqlSessionFactory 的最佳作用域是应用作用域。最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。下面的示例就是一个确保 SqlSession 关闭的标准模式:

try (SqlSession session = sqlSessionFactory.openSession()) {
// 你的应用逻辑代码
}

在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。

Mybatis学习-配置、作用域和生命周期的更多相关文章

  1. 学习MyBatis必知必会(5)~了解myBatis的作用域和生命周期并抽取工具类MyBatisUtil、mybatis执行增删改查操作

    一.了解myBatis的作用域和生命周期[错误的使用会导致非常严重的并发问题] (1)SqlSessionFactoryBuilder [ 作用:仅仅是用来创建SqlSessionFactory,作用 ...

  2. MyBatis 作用域和生命周期

    理解到目前为止所讨论的类的作用域和生命周期是非常重要的.如果使用不当可导致严重的并发性问题. SqlSessionFactoryBuilder  这个类可以在任何时候被实例化.使用和销毁.一旦您创造了 ...

  3. Bean 注解(Annotation)配置(2)- Bean作用域与生命周期回调方法配置

    Spring 系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of ...

  4. Bean XML 配置(2)- Bean作用域与生命周期回调方法配置

    系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of Contro ...

  5. MyBatis(四):SqlSession及其工厂类的作用域和生命周期

    本文是按照狂神说的教学视频学习的笔记,强力推荐,教学深入浅出1便就懂!b站搜索狂神说即可 https://space.bilibili.com/95256449?spm_id_from=333.788 ...

  6. Spring之Bean的作用域与生命周期

    在前面博客中提到容器启动获得BeanDefinition对象中有一个scope 属性.该属性控制着bean对象的作用域.本章节介绍Bean的作用域及生命周期,了解bean是怎么来的又怎么没的. 一.B ...

  7. 详解Spring中Bean的作用域与生命周期

    摘要:在利用Spring进行IOC配置时,关于bean的配置和使用一直都是比较重要的一部分,同时如何合理的使用和创建bean对象,也是小伙伴们在学习和使用Spring时需要注意的部分,所以这一篇文章我 ...

  8. Spring中Bean的作用域、生命周期

                                   Bean的作用域.生命周期 Bean的作用域 Spring 3中为Bean定义了5中作用域,分别为singleton(单例).protot ...

  9. spring作用、spring注解、管理对象的作用域与生命周期、自动装配、Spring的框架包有哪些作用是什么

    Spring 1. 作用 创建和管理对象,使得开发过程中,可以不必使用new关键字创建对象,而是直接获取对象!并且,还可以通过一些配置,使得某些获取到的对象,其中某些属性已经是被赋值的! 2. Spr ...

随机推荐

  1. Java入门(4)

    阅读书目:Java入门经典(第7版) 作者:罗格斯·卡登海德 面向对象编程(OOP)将程序视为对象的集合,确定程序要完成的任务,然后将这些任务指派给最适合完成它们的对象.换言之,计算机程序是一组对象, ...

  2. week01-绪论作业

    一.有理数的抽象数据模型 ADT Rational { 数据对象: D={e1,e2|e1,e2属于ElemType类型}//ElemType为自定义的整数集合类型 数据关系: R={<e1,e ...

  3. 7、Python语法之与用户交互、运算符

    一 .程序与用户交互 1.1.什么是与用户交互 用户交互就是人往计算机中input/输入数据,计算机print/输出结果. 1.2.为什么要与用户交互 为了让计算机能够像人一样与用户沟通交流. 比如, ...

  4. python爬虫构建代理ip池抓取数据库的示例代码

    爬虫的小伙伴,肯定经常遇到ip被封的情况,而现在网络上的代理ip免费的已经很难找了,那么现在就用python的requests库从爬取代理ip,创建一个ip代理池,以备使用. 本代码包括ip的爬取,检 ...

  5. Windows defender历史记录闪退解决方案

    删除C:\ProgramData\Microsoft\Windows defender\Scans\History\Service文件夹 另外defender可以设置保护文件夹,选择病毒和威胁防护-管 ...

  6. http代理阅读3 发送mem处理

    每次客户端有可读数据触发时,优先检测是否还有数据没有发送,如果有则发送数据,然后在读取client数据 //向后端发送请求的调用过程 //ngx_http_upstream_send_request_ ...

  7. Kafka 生产者分区策略

    分区策略 1)分区的原因 (1)方便在集群中扩展,每个 Partition 可以通过调整以适应它所在的机器,而一个 topic 又可以有多个 Partition 组成,因此整个集群就可以适应任意大小的 ...

  8. UNP第13章——守护进程

    1. 守护进程的启动方法 (1)系统初始化脚本启动,在系统启动阶段,按照如/etc目录或/etc/rc开头的目录中的某些脚本启动,这些守护进程一开始就有超级用户权限.如inetd,cron,Web服务 ...

  9. rgw配置删除快速回收对象

    前言 做rgw测试的时候,经常会有删除文件的操作,而用默认的参数的时候,rgw是通过gc回收机制来处理删除对象的,这个对于生产环境是有好处的,把删除对业务系统的压力分摊到不同的时间点,但是测试的时候, ...

  10. C# 9.0新特性详解系列之一:只初始化设置器(init only setter)

    1.背景与动机 自C#1.0版本以来,我们要定义一个不可变数据类型的基本做法就是:先声明字段为readonly,再声明只包含get访问器的属性.例子如下: struct Point { public ...