核心配置文件: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. The Product-Minded Software Engineer

    转自The Product-Minded Software Engineer Product-minded engineers are developers with lots of interest ...

  2. Servlet程序访问jsp文件404的一种情况

    启动Jsp Run on Server的时候出现404的错误,如下图: 检查一下是否文档目录如下图:jsp应该在WebContent下,而不是WEB_INF下,访问放在WEB_INF下的jsp文件就会 ...

  3. opencv--ORB::create

    static Ptr<ORB> cv::ORB::create (                         int nfeatures = 500,                 ...

  4. python_选课系统

    import sys import pickle import os USERINFO = r'C:\Users\12078\PycharmProjects\OldBoy\选课系统\userinfo' ...

  5. mysql 定时任务执行

    SET GLOBAL event_scheduler = ON; show variables like 'event_scheduler'; event_scheduler ON 创建event: ...

  6. 虚拟DOM与diff算法

    虚拟DOM与diff算法 虚拟DOM 在DOM操作中哪怕我们的数据,发生了一丢丢的变化,也会被强制重建整预DOM树.这么做,涉及到很多元素的重绘和重排,导致性能浪费严重 只要实现按需更新页面上的元素即 ...

  7. nginx&http 第二章 ngx 事件event初始化 ngx_event_process_init

    |----------(ngx_worker_process_cycle->ngx_worker_process_init) |--------->for(;;) {ngx_process ...

  8. JsonPath在接口自动化中的应用

    我理解jsonpath于json而言,就像是xpath在XML中的作用.用来确定json中某部分数据的语言.我更喜欢叫jsonpath表达式,因为这样好像是数学问题. 以前和小伙伴一起写接口自动化的时 ...

  9. this.getClass().getResource("") url path file 区别

    首先注意 "/word/appointDismiss.docx" 前面一定要加 /,有一次我就是忘记加/ 查了半天错, 不能写成 "word/appointDismiss ...

  10. 网络发布工具 Apache/Nginx

    四大主流发布服务器 注:发布服务器的背后都是socket套接字 1.Apache阿帕奇 - 多进程 2.IIS -多线程 3.Nginx (engine x)(新) -支持异步IO,是现在最快的发布服 ...