MyBatis 02 配置
导入jar包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
jar包版本可自行选中,建议选择使用人数最多的。
编写核心配置文件
<?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文件-->
<properties resource="db.properties"/>
<!--配置,必须在properties以下,否则会报错-->
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
<!--别名-->
<typeAliases>
<package name="cn.sail.model"/>
</typeAliases>
<!--环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--映射-->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
能配置的内容如下:
configuration:配置
properties:属性
settings:设置
typeAliases:类型别名
typeHandlers:类型处理器
objectFactory:对象工厂
plugins:插件
environments:环境配置
environment:环境变量
transactionManager:事务管理器
dataSource:数据源
property:元素
databaseIdProvider:数据库厂商标识
mappers:映射器
注意元素节点的顺序,顺序不对会报错。
properties
数据库这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。具体的官方文档
我们来优化我们的配置文件
在资源目录下新建一个db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username=root
password=123456
将文件导入properties 配置文件
<?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文件-->
<properties resource="db.properties"/>
</configuration>
settings
<!--配置,必须在properties以下,否则会报错-->
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 |
true | false | false |
aggressiveLazyLoading | 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods )。 |
true | false | false (在 3.4.1 及之前的版本中默认为 true) |
multipleResultSetsEnabled | 是否允许单个语句返回多结果集(需要数据库驱动支持)。 | true | false | true |
useColumnLabel | 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 | true | false | true |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 | true | false | False |
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL |
autoMappingUnknownColumnBehavior | 指定发现自动映射目标未知列(或未知属性类型)的行为。NONE : 不做任何反应WARNING : 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN )FAILING : 映射失败 (抛出 SqlSessionException ) |
NONE, WARNING, FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定数据库驱动等待数据库响应的秒数。 | 任意正整数 | 未设置 (null) |
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | 未设置 (null) |
defaultResultSetType | 指定语句默认的滚动策略。(新增于 3.5.2) | FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置) | 未设置 (null) |
safeRowBoundsEnabled | 是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 | true | false | False |
safeResultHandlerEnabled | 是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。 | true | false | True |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。 | SESSION | STATEMENT | SESSION |
jdbcTypeForNull | 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 | JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。 | OTHER |
lazyLoadTriggerMethods | 指定对象的哪些方法触发一次延迟加载。 | 用逗号分隔的方法列表。 | equals,clone,hashCode,toString |
defaultScriptingLanguage | 指定动态 SQL 生成使用的默认脚本语言。 | 一个类型别名或全限定类名。 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
defaultEnumTypeHandler | 指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5) |
一个类型别名或全限定类名。 | org.apache.ibatis.type.EnumTypeHandler |
callSettersOnNulls | 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。 | true | false | false |
returnInstanceForEmptyRow | 当返回行的所有列都是空时,MyBatis默认返回 null 。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2) |
true | false | false |
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | 任何字符串 | 未设置 |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
proxyFactory | 指定 Mybatis 创建可延迟加载对象所用到的代理工具。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 以上) |
vfsImpl | 指定 VFS 的实现 | 自定义 VFS 的实现的类全限定名,以逗号分隔。 | 未设置 |
useActualParamName | 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1) |
true | false | true |
configurationFactory | 指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3) |
一个类型别名或完全限定类名。 | 未设置 |
shrinkWhitespacesInSql | 从SQL中删除多余的空格字符。请注意,这也会影响SQL中的文字字符串。 (新增于 3.5.5) | true | false | false |
defaultSqlProviderType | Specifies an sql provider class that holds provider method (Since 3.5.6). This class apply to the type (or value ) attribute on sql provider annotation(e.g. @SelectProvider ), when these attribute was omitted. |
A type alias or fully qualified class name | Not set |
typeAliases
类型别名是为 Java 类型设置一个短的名字。
它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。
方式一:指定具体类
<typeAliases>
<typeAlias type="cn.sail.model.entity.User" alias="user"/>
</typeAliases>
当这样配置时,user
可以用在任何使用cn.sail.model.entity.User
的地方。
方式二:指定包名
<typeAliases>
<package name="cn.sail.model"/>
</typeAliases>
MyBatis 会在包名下面搜索需要的 Java Bean。
在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。
方式三:使用注解
@Alias("user")
public class User {
}
有注解的情况下,则以注解中的别名为准。
environments
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
配置 MyBatis 的多套运行环境,将 SQL 映射到多个不同的数据库上,必须指定其中一个为默认运行环境(通过 default 指定)
environment子元素节点
transactionManager事务管理器
支持两种类型
type="[JDBC|MANAGED]"
JDBC
事务管理器被用作当应用程序负责管理数据库连接的生命周期(提交、回退等等)的时候。
设置成此属性时,MyBatis 内部将使用 JdbcTransactionFactory 类创建 TransactionManager。
MANAGED
事务管理器是当由应用服务器负责管理数据库连接生命周期的时候使用。设置成此属性时,MyBatis 内部使用 ManagedTransactionFactory 类创建事务管理器TransactionManager。
这两种事务管理器类型都不需要设置任何属性。
Managed 是托管的意思,即是应用本身不去管理事务,而是把事务管理交给应用所在的服务器进行管理。
dataSource数据源
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
数据源是必须配置的。
有三种内建的数据源类型。
type="[UNPOOLED|POOLED|JNDI]")
UNPOOLED
这个数据源的实现只是每次被请求时打开和关闭连接。
POOLED
这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来 , 这是一种使得并发 Web 应用快速响应请求的流行处理方式。
JNDI
这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
数据源也有很多第三方的实现,比如 dbcp、c3p0、druid 等。
mappers
映射器 : 定义映射 SQL 语句文件
既然 MyBatis 的行为其他元素已经配置完了,我们现在就要定义 SQL 映射语句了。
首先我们需要告诉 MyBatis 到哪里去找到这些语句。
Java 在自动查找这方面没有提供一个很好的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。
你可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:///
的 URL),或类名和包名等。
在 MyBatis 3 之前,只支持 xml 映射器,所有的 SQL 语句都必须在 xml 文件中配置。
从 MyBatis 3 开始,还支持接口映射器,这种映射器方式允许以 Java 代码的方式注解定义 SQL 语句,非常简洁。
引入资源方式
使用相对于类路径的资源引用
<mappers>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
使用完全限定资源定位符
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
使用映射器接口实现类的完全限定类名
需要配置文件名称和接口名称一致,并且位于同一目录下
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
将包内的映射器接口实现全部注册为映射器
需要配置文件名称和接口名称一致,并且位于同一目录下
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
编写工具类
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// 获取SqlSession连接
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}
创建实体类
@Data
public class User {
/**
* 主键
*/
private int id;
/**
* 姓名
*/
private String name;
/**
* 密码
*/
private String pwd;
}
编写Mapper接口类
public interface UserMapper {
/**
* 查询用户列表
* @return 用户列表
*/
List<User> selectList();
}
编写Mapper.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sail.mapper.UserMapper">
<select id="selectList" resultType="com.sail.model.entity.User">
select id,
name,
pwd
from user;
</select>
</mapper>
namespace的值应为对应Mapper接口类的包路径,由此才能与该接口类建立关联。
标签id的值应为对应Mapper接口类的方法名,由此才能与该方法建立关联。
测试
@Test
public void testMyBatis() {
SqlSession sqlSession = MybatisUtils.getSession();
// 方式一
List<User> userList = sqlSession.selectList("com.sail.mapper.UserMapper.selectList");
// 方式二(推荐)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userList = userMapper.selectList();
for (User user : userList) {
System.out.println(user);
}
}
方式二的方法调用更为直观,现在普遍使用,推荐用这种方式。
可能出现的问题
Maven静态资源过滤问题
可以在 pom 文件中编写如下代码解决:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
类型处理器
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型。
对象工厂
MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。
默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过有参构造方法来实例化。
如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。
生命周期和作用域
作用域和生命周期是至关重要的,因为错误的使用会导致非常严重的并发问题。
Mybatis 的执行过程如下图:
SqlSessionFactoryBuilder
SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用。
它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。
SqlSessionFactoryBuilder 的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory
SqlSessionFactory 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象。
MyBatis 的本质就是 Java 对数据库的操作,所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中。
一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用。
可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。
由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。
如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。
因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。
SqlSessionFactory 的最佳作用域是应用作用域。
SqlSession
如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相当于一个数据库连接(Connection 对象)。
在一个事务里面可以执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务。
它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪。所以用 try...catch...finally... 语句来保证其正确关闭。
SqlSession 的最佳作用域是请求或方法作用域。