核心配置文件

核心配置文件中的标签必须按照固定的顺序(有的标签可以不写,但顺序一定不能乱):
properties、settings、typeAliases、typeHandlers、objectFactory、objectWrapperFactory、reflectorFactory、plugins、environments、databaseIdProvider、mappers

image.png
下面介绍上图中几个常用的标签

environments标签

  1. <environments default="development">
  2. <environment id="development">
  3. <transactionManager type="JDBC">
  4. <property name="..." value="..."/>
  5. </transactionManager>
  6. <dataSource type="POOLED">
  7. <property name="driver" value="${driver}"/>
  8. <property name="url" value="${url}"/>
  9. <property name="username" value="${username}"/>
  10. <property name="password" value="${password}"/>
  11. </dataSource>
  12. </environment>
  13. </environments>

解释几个重要的标签:
中的id是环境唯一标识符,MyBatis允许拥有多套运行环境,将SQL映射到多个不同的数据库上,但必须指定其中一个为默认运行环境(通过default指定);
是指定事务管理器的标签,一般只有两种事务管理器,JDBC和MANAGED,但后者通常不会使用,了解即可;
用于用于配置数据源的标签,数据源是必须配置的,dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源,一般有三种内建的数据源类型:

  • unpooled: 这个数据源的实现只是每次被请求时打开和关闭连接。
  • pooled: 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来 , 这是一种使得并发 Web 应用快速响应请求的流行处理方式。
  • jndi:这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。

其中一般使用pooled(默认),当然也有很多第三方数据源:dbcp、c3p0、druid…

Properties优化

数据库这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过properties 元素的子元素来传递。
首先将数据库连接配置写到配置文件:

  1. driver=com.mysql.cj.jdbc.Driver
  2. url=jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8
  3. username=root
  4. password=wujiahao269139

然后在核心配置文件里面导入db.properties即可:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//MyBatis.org//DTD Config 3.0//EN"
  4. "http://MyBatis.org/dtd/MyBatis-3-config.dtd">
  5. <configuration>
  6. <!--引入properties文件,此时就可以${属性名}的方式访问属性值-->
  7. <properties resource="jdbc.properties"></properties>
  8. <settings>
  9. <!--将表中字段的下划线自动转换为驼峰-->
  10. <setting name="mapUnderscoreToCamelCase" value="true"/>
  11. <!--开启延迟加载-->
  12. <setting name="lazyLoadingEnabled" value="true"/>
  13. </settings>
  14. <typeAliases>
  15. <!--
  16. typeAlias:设置某个具体的类型的别名
  17. 属性:
  18. type:需要设置别名的类型的全类名
  19. alias:设置此类型的别名,且别名不区分大小写。若不设置此属性,该类型拥有默认的别名,即类名
  20. -->
  21. <!--<typeAlias type="com.atguigu.mybatis.bean.User"></typeAlias>-->
  22. <!--<typeAlias type="com.atguigu.mybatis.bean.User" alias="user">
  23. </typeAlias>-->
  24. <!--以包为单位,设置改包下所有的类型都拥有默认的别名,即类名且不区分大小写-->
  25. <package name="com.atguigu.mybatis.bean"/>
  26. </typeAliases>
  27. <!--
  28. environments:设置多个连接数据库的环境
  29. 属性:
  30. default:设置默认使用的环境的id
  31. -->
  32. <environments default="mysql_test">
  33. <!--
  34. environment:设置具体的连接数据库的环境信息
  35. 属性:
  36. id:设置环境的唯一标识,可通过environments标签中的default设置某一个环境的id,表示默认使用的环境
  37. -->
  38. <environment id="mysql_test">
  39. <!--
  40. transactionManager:设置事务管理方式
  41. 属性:
  42. type:设置事务管理方式,type="JDBC|MANAGED"
  43. type="JDBC":设置当前环境的事务管理都必须手动处理
  44. type="MANAGED":设置事务被管理,例如spring中的AOP
  45. -->
  46. <transactionManager type="JDBC"/>
  47. <!--
  48. dataSource:设置数据源
  49. 属性:
  50. type:设置数据源的类型,type="POOLED|UNPOOLED|JNDI"
  51. type="POOLED":使用数据库连接池,即会将创建的连接进行缓存,下次使用可以从缓存中直接获取,不需要重新创建
  52. type="UNPOOLED":不使用数据库连接池,即每次使用连接都需要重新创建
  53. type="JNDI":调用上下文中的数据源
  54. -->
  55. <dataSource type="POOLED">
  56. <!--设置驱动类的全类名-->
  57. <property name="driver" value="${jdbc.driver}"/>
  58. <!--设置连接数据库的连接地址-->
  59. <property name="url" value="${jdbc.url}"/>
  60. <!--设置连接数据库的用户名-->
  61. <property name="username" value="${jdbc.username}"/>
  62. <!--设置连接数据库的密码-->
  63. <property name="password" value="${jdbc.password}"/>
  64. </dataSource>
  65. </environment>
  66. </environments>
  67. <!--引入映射文件-->
  68. <mappers>
  69. <!-- <mapper resource="UserMapper.xml"/> -->
  70. <!--
  71. 以包为单位,将包下所有的映射文件引入核心配置文件
  72. 注意:
  73. 1. 此方式必须保证mapper接口和mapper映射文件必须在相同的包下
  74. 2. mapper接口要和mapper映射文件的名字一致
  75. -->
  76. <package name="com.atguigu.mybatis.mapper"/>
  77. </mappers>
  78. </configuration>

其中中,如db.properties的key和其子标签的key重名,则外部配置文件(也就是db.properties)的优先级更高

typeAliases(类型别名)优化

mapper标签中的namespace需要采用完整的po类名,不能使用简化的类名,十分的麻烦和冗余,因此可以给他起个别名,一般来说有两种方式。
方式一:直接给po类规定一个简化的名字

  1. <typeAliases>
  2. <typeAlias type="com.wjh.po.User" alias="user"/>
  3. </typeAliases>

当这样配置时,user可以用在任何使用com.kuang.pojo.User的地方。
方式二:通过注解来给po类起别名
先指定一个需要被扫描的包名,如果该包里面的类有注解则使用其注解的内容,没有注解则默认使用 Bean 的首字母小写的非限定类名(即简单的类名)来作为它的别名

  1. <typeAliases>
  2. <package name="com.wjh.po"/>
  3. </typeAliases>

标上Alias注解的格式:

  1. @Alias("user")
  2. public class User {
  3. ...
  4. }

下面是官方给出的一些为常见的 Java 类型内建的类型别名,它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

Mapper映射

既然 MyBatis 的行为已经由上述元素配置完了,现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用(推荐使用),或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:

  1. <!-- 使用相对于类路径的资源引用 --> //推荐使用该方式注册
  2. <mappers>
  3. <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  4. <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  5. <mapper resource="org/mybatis/builder/PostMapper.xml"/>
  6. </mappers>
  1. <!-- 使用完全限定资源定位符(URL) -->
  2. <mappers>
  3. <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  4. <mapper url="file:///var/mappers/BlogMapper.xml"/>
  5. <mapper url="file:///var/mappers/PostMapper.xml"/>
  6. </mappers>
  1. <!-- 使用映射器接口实现类的完全限定类名 -->
  2. <mappers>
  3. <mapper class="org.mybatis.builder.AuthorMapper"/>
  4. <mapper class="org.mybatis.builder.BlogMapper"/>
  5. <mapper class="org.mybatis.builder.PostMapper"/>
  6. </mappers>
  1. <!-- 将包内的映射器接口实现全部注册为映射器 -->
  2. <mappers>
  3. <package name="org.mybatis.builder"/>
  4. </mappers>

注意使用class配置时:接口和它的Mapper配置文件必须同名并且在同一个包下面

setting标签

setting可以设置很多东西,这里主要讲一下MyBatis中日志的设置
Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:
SLF4J
Apache Commons Logging
Log4j 2
Log4j
JDK logging
标准日志实现(STDOUT_LOGGING)

  1. <settings>
  2. <setting name="logImpl" value="STDOUT_LOGGING"/>
  3. </settings>

日志输出的格式如下:
image.png
但是这个设置只能将日志输出到控制台,下面介绍比较优秀的第三方日志:log4j
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地:控制台,文本,GUI组件….我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
首先需要导入log4j依赖:

  1. <dependency>
  2. <groupId>log4j</groupId>
  3. <artifactId>log4j</artifactId>
  4. <version>1.2.17</version>
  5. </dependency>

其次编写log4j的配置文件(可根据需求更改value):

  1. #将等级为DEBUG的日志信息输出到consolefile这两个目的地,consolefile的定义在下 面的代码
  2. log4j.rootLogger=DEBUG,console,file
  3. #控制台输出的相关设置
  4. log4j.appender.console=org.apache.log4j.ConsoleAppender
  5. log4j.appender.console.Target=System.out
  6. log4j.appender.console.Threshold=DEBUG
  7. log4j.appender.console.layout=org.apache.log4j.PatternLayout
  8. log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
  9. #文件输出的相关设置
  10. log4j.appender.file=org.apache.log4j.RollingFileAppender
  11. log4j.appender.file.File=./log/log4j.log
  12. log4j.appender.file.MaxFileSize=10mb
  13. log4j.appender.file.Threshold=DEBUG
  14. log4j.appender.file.layout=org.apache.log4j.PatternLayout
  15. log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
  16. #日志输出级别
  17. log4j.logger.org.mybatis=DEBUG
  18. log4j.logger.java.sql=DEBUG
  19. log4j.logger.java.sql.Statement=DEBUG
  20. log4j.logger.java.sql.ResultSet=DEBUG
  21. log4j.logger.java.sql.PreparedStatement=DEBUG

如果需要实现不同等级的日志,需要先在需要被日志记录的类里面创建一个logger对象
image.png
日志输出到文件的结果:
image.png

生命周期和作用域

不同作用域和生命周期类是至关重要的,因为错误的使用会导致非常严重的并发问题。先看一下MyBatis的执行流程图:
image.png
然后看一下官方的注释:
依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期。 如果对如何通过依赖注入框架使用 MyBatis 感兴趣,可以研究一下 MyBatis-Spring 或 MyBatis-Guice 两个子项目。

SqlSessionFactoryBuilder

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

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) {
// 你的应用逻辑代码
}
在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。

image.png

通俗解释

SqlSessionFactoryBuilder:

一旦创建了SqlSessionFactory就不再需要它了,是一个局部变量

SqlSessionFactory:

可以想象为数据库连接池,一旦被创建就会在程序的整个运行期间存在,没有任何理由丢弃它或重新创建一个实例,因此它的最佳作用域是应用作用域,最简单的就是使用单例模式或静态单例模式

SqlSession:

可以理解为连接到连接池的一个请求,它的实例不是线程安全的,因此不能被共享,所以它的最佳作用域是请求或方法作用域,并且用完之后需要立刻被关闭,否则会导致资源被占用