1、MyBatis的简介
1.1 MyBatis是什么的框架
• MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
• MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
• MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录.
1.2 MyBatis的历史
• MyBatis原是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了Google Code,随着开发团队转投Google Code旗下, iBatis3.x正式更名为MyBatis ,代码于2013年11月迁移到Github(下载地址:https://github.com/mybatis/mybatis-3/)。
• iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
1.3 为什么使用MyBatis
• MyBatis是一个半自动化的持久化层框架。
• JDBC的缺点:
– SQL夹在Java代码块里,耦合度高导致硬编码内伤;
– 维护不易,且实际开发需求中sql是有变化,频繁修改的情况多见。
• Hibernate和JPA
– 长难复杂SQL,对于Hibernate而言处理也不容易;
– 内部自动生产的SQL,不容易做特殊优化;
– 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难,导致数据库性能下降。
• 对开发人员而言,核心sql还是需要自己优化;
• sql 和 java 编码分开,功能边界清晰,一个专注业务、一个专注数据 。而MyBatis正好满足这些需求。
2、入门程序
下面我们就通过一个简单的代码了解一下,MyBatis是如何操作数据库,并把数据库中的一行记录封装成一个Java对象的。
2.1 数据库准备
创建数据库,并插入一条记录:
CREATE TABLE t_employee(
id VARCHAR(20) PRIMARY KEY,
last_name VARCHAR(100),
age INT,
addr VARCHAR(200)
);
INSERT INTO t_employee VALUES ('1','tom',22,'changshashi');
2.2 创建普通的Java工程
本次使用的工具是IDEA,他创建Java工程跟Eclipse有不同,所以简单讲解下:
2.2.1 创建普通工程
File——》new ——》Project——》Java——》JavaEE,然后一路next知道完成。
2.2.2 添加jar包到工程中
本次需要用到的jar包:mybatis的包,mysql的驱动包,log4j的日志包,这些jar包都在Mybatis的下载中包含了。我们首先要把这几个包放到同一个目录下面,然后在IDEA中操作:
File——》Project Structure...——》Libraries——》点击+号,选择Java——》然后选择我们刚才存放jar包的目录即可。
我们就可以在工程的 External Libraries下面看到我们刚才引的jar包的目录,里面有我们需要的jar包了。
2.2.3 创建资源文件夹
在工程的根目录下面,创建一个conf的资源文件夹,用来存放一些MyBatis的配置文件,Java类的映射文件以及其他配置文件(比如日志文件)。
右键工程名——》new——》Directory——》文件名称为:conf
右键conf目录——》Mark Directory as——》Resources Root,那么这个conf就变成了资源目录了。
2.2.4 创建配置文件
首先把log4j的配置文件放到conf目录下,log4j.xml配置文件,在MyBatis的下载中有;
创建MyBatis的主配置文件: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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis3" />
<property name="username" value="root" />
<property name="password" value="123" />
</dataSource>
</environment>
</environments>
<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 -->
<mappers>
<mapper resource="EmployeeMapper.xml" />
</mappers>
</configuration>
里面有关数据库的配置,要根据自己的情况来配置。特别需要注意的是,<mappers>标签里面配置的Java类的映射文件的信息,这里配置的是:resource="EmployeeMapper.xml",意思是会找到项目根目录下的该文件,所以我们还需要在conf目录下面创建改文件。
创建映射文件:EmployeeMapper.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.mybatis.EmployeeMapper">
<!--
namespace:名称空间;指定为接口的全类名
id:唯一标识
resultType:返回值类型
#{id}:从传递过来的参数中取出id值
-->
<select id="getEmpById" resultType="com.mybatis.pojo.Employee">
select id,last_name lastName,age,addr from t_employee where id = #{id}
</select>
</mapper>
2.3 代码编写
2.3.1 创建Java类
创建一个Java类,跟我们的t_employee表对应的
package com.mybatis.pojo;
public class Employee {
private String id;
private String lastName;
private int age;
private String addr;
//get/set方法以及toString方法
}
2.3.2 编写测试类
编写测试类,根据id查询数据库中记录
package com.mybatis.test;
import com.mybatis.pojo.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisTest {
private SqlSessionFactory sessionFactory = null;
//@Before注解:表示在执行其他方法之前,会先执行该方法,常用来做初始化操作
@Before
public void init() throws IOException {
String resourceFile = "mybatis-config.xml";
//加载主配置文件
InputStream inputStream = Resources.getResourceAsStream(resourceFile);
//得到SqlSessionFactory
sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void test1() {
SqlSession sqlSession = null;
try {
//得到sqlSession
sqlSession = sessionFactory.openSession();
//执行sql
Employee employee = sqlSession.selectOne("com.mybatis.EmployeeMapper.getEmpById", "1");
System.out.println(employee);
}catch (Exception e){
e.printStackTrace();
}finally {
if(sqlSession!=null){
sqlSession.close();//释放资源
}
}
}
}
运行结果:Employee{id='1', lastName='tom', age=22, addr='changshashi'}
2.4 总结
上面的程序,就是简单的通过MyBatis访问数据库,并对查询到的结果进行封装,给我们返回的是我们需要的Java对象。
特别需要注意的是:
主配置文件mybatis-config.xml中,数据库相关的配置要正确;映射文件的配置不能搞错了;
映射文件中,sql片段的id不能重复;映射文件中的查询语句的字段如果跟Java对象的属性名称不一样,那么就要使用别名的方式使其一致,才能把数据映射成功,比如上面的last_name字段。
3、接口式编程
上面的 2 中,进行测试的时候,我们的sql语句唯一标识,以及参数,都是我们手动去指定,并且没有类型规定的,这样就会造成如果写错了,那么就得不到想要的结果。
MyBatis给我们提供了接口式编程的方法,我们只要编写接口,把接口的方法和映射文件的sql的id对应,那么不需要写接口的实现,就可以完成对数据库的增删改查操作。
3.1 编写接口
package com.mybatis.mapper;
import com.mybatis.pojo.Employee;
public interface EmployeeMapper {
//根据id查询的方法
public Employee selectById(String id);
}
3.2 修改映射文件
<?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.mybatis.EmployeeMapper">-->
<mapper namespace="com.mybatis.mapper.EmployeeMapper">
<!--
namespace:名称空间;指定为接口的全类名
id:唯一标识
resultType:返回值类型
#{id}:从传递过来的参数中取出id值
public Employee selectById(String id);
-->
<select id="selectById" resultType="com.mybatis.pojo.Employee">
select id,last_name lastName,age,addr from t_employee where id = #{id}
</select>
</mapper>
此时的映射文件的namespace的值是我们的接口的全类名,这样就把该映射文件和我们的接口做了绑定,而sql语句的id=selectById,就对应的是接口中的方法名,把sql和我们的方法绑定了,sql的resultType对应的就是我们的方法中的返回值。
3.3 测试方法
@Test
public void test2(){
SqlSession sqlSession = null;
try {
sqlSession = sessionFactory.openSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
System.out.println("mapper对象:"+employeeMapper);
Employee employee = employeeMapper.selectById("1");
System.out.println(employee);
}finally {
sqlSession.close();
}
}
结果:
mapper对象:org.apache.ibatis.binding.MapperProxy@3632be31
Employee{id='1', lastName='tom', age=22, addr='changshashi'}
3.4 总结
接口式编程的好处:
接口定义了规范:返回值,参数类型等,而且起到解耦作用,这里使用的MyBatis来实现,我们也可以使用其他的持久层框架进行实现。这种方式以后用的最多。
4、SqlSession
• SqlSession 的实例不是线程安全的,因此是不能被共享的(不要放在成员变量中)。
• SqlSession 每次使用完成后需要正确关闭,这个关闭操作是必须的
• SqlSession 可以直接调用方法的id进行数据库操作,但是我们一般还是推荐使用SqlSession获取到Dao接口的代理类,执行代理对象的方法,可以更安全的进行类型检查操作。
5、MyBatis的全局配置文件
MyBatis 的配置文件包含了影响 MyBatis 行为甚深的设置(settings)和属性(properties)信息。文档的顶层结构如下:
• configuration 配置
• properties 属性
• settings 设置
• typeAliases 类型命名
• typeHandlers 类型处理器
• objectFactory 对象工厂
• plugins 插件
• environments 环境
• environment 环境变量
• transactionManager 事务管理器
• dataSource 数据源
• databaseIdProvider 数据库厂商标识
• mappers 映射器
5.1 properties属性
mybatis可以使用properties来引入外部properties配置文件的内容,常用来引入数据库的配置;
resource:引入类路径下的资源
url:引入网络路径或者磁盘路径下的资源
5.1.1 创建db.properties
在工程的资源文件目录conf下面,创建db.properties文件,里面配置了数据库的相关配置:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis3
jdbc.username=root
jdbc.password=123
5.1.2 在mybatis-config.xml引入properties
在全局配置文件mybatis-config.xml中,通过<properties>引入db.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 resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<!--事务管理器-->
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 -->
<mappers>
<mapper resource="EmployeeMapper.xml" />
</mappers>
</configuration>
5.1.3 测试
这样修改之后,我们再次运行之前的测试方法,运行都是正常的。
5.1.4 注意
• 如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:
– 在 properties 元素体内指定的属性首先被读取。
– 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
– 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
5.2 settings设置
这是 MyBatis 中极为重要的调整设置,它们会改变MyBatis 的运行时行为。下表描述了设置中各项的意图、默认值等。
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
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, FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库响应的秒数。 | 任意正整数 | 未设置 (null) |
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | 未设置 (null) |
defaultResultSetType | Specifies a scroll strategy when omit it per statement settings. (Since: 3.5.2) | FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(same behavior with 'Not Set') | Not Set (null) |
safeRowBoundsEnabled | 允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 | true | false | False |
safeResultHandlerEnabled | 允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为 false。 | true | false | True |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true | false | False |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 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) | 类型别名或者全类名. | 未设置 |
5.2.1 mapUnderscoreToCamelCase
我们以mapUnderscoreToCamelCase为例,讲解一下settings的使用。我们知道,在映射文件中,编写sql的时候,如果数据库中的字段和我们java类的属性名称是不同的,那么查询的时候,就无法把数据库的数据封装到Java对象的属性中。因此我们上面的sql中,使用了别名来处理这个:
<select id="selectById" resultType="com.mybatis.pojo.Employee">
select id,last_name lastName,age,addr from t_employee where id = #{id}
</select>
last_name是数据库中字段名,lastName是java类的属性名称。
之所以要这样处理,是因为mapUnderscoreToCamelCase 属性的值默认是false,也就是不开启驼峰命名规则。如果我们把mapUnderscoreToCamelCase的值设置为true,那么,MyBatis会自动把last_name字段用驼峰命名的方式封装到属性lastName中。
在mybatis-config.xml中,添加如下配置:
<settings>
<!--开启驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
这时,我们的映射文件的sql就不需要使用别名了:
<select id="selectById" resultType="com.mybatis.pojo.Employee">
select id,last_name,age,addr from t_employee where id = #{id}
</select>
5.3 typeAliases别名处理器
在上面的映射文件中,sql的resultType的值是我们Employee类的全类名,这样其实挺好的,建议这样使用,只是写起来麻烦点。
当然,如果觉得这样不方便,MyBatis提供了typeAliases别名处理器,可以给我们的Java类取一个别名,这样我们在使用这个Java类的时候,不需要使用全类名,使用其对应的简短别名就可以了。
可以有三种方式来给Java类起别名:
5.3.1 单个起别名
在settings的下面,使用typeAliases给类起别名:
<!--别名处理-->
<typeAliases>
<typeAlias type="com.mybatis.pojo.Employee" alias="emp"/>
</typeAliases>
如果alias的值为空,那么默认的别名就是Employee类名下小写。(其实别名不区分大小写)
5.3.2 包扫描
类很多的情况下,可以批量设置别名这个包下的每一个类创建一个默认的别名,就是简单类名小写。
<typeAliases>
<package name="com.mybatis.pojo"/>
</typeAliases>
5.3.3 注解@Aliase
当我们使用包扫描的时候,如果pojo包下面还有子包,子包里面也有一个Employee类,那么这样的话,他们的默认别名都是employee,无法进行区分,当引用的时候,就会报错了,这个时候可以使用注解@Aliase(org.apache.ibatis.type.Alias)来给不同的Employee起别名,比如:
@Alias("emp")
public class Employee {
这样的话,我们的别名就不是employee了,而是emp。
5.3.4 MyBatis默认别名
值得注意的是, MyBatis 已经 为许多常见的 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 |
5.4 typeHandlers 类型 处理器
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。点击查看默认的类型处理器
5.4.1 日期类型的处理
• 日期和时间的处理,JDK1.8以前一直是个头疼的问题。我们通常使用JSR310规范领导者StephenColebourne创建的Joda-Time来操作。1.8已经实现全部的JSR310规范了。
• 日期时间处理上,我们可以使用MyBatis基于JSR310(Date and Time API)编写的各种日期时间类型处理器。
• MyBatis3.4.5 以前的版本需要我们手动注册这些处理器,以后的版本都是自动注册的
5.4.2 自定义类型处理器
• 我们可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型。
• 步骤:
• 1)、实现org.apache.ibatis.type.TypeHandler接口或者继承org.apache.ibatis.type.BaseTypeHandler
• 2)、指定其映射某个JDBC类型(可选操作)
• 3)、在mybatis全局配置文件中注册
5.5 plugins插件
• 插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行。后面会详细的介绍mybatis运行原理以及插件。
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为如果在试图修改或重写已有方法的行为的时候,你很可能在破坏 MyBatis 的核心模块。 这些都是更低层的类和方法,所以使用插件的时候要特别当心。
通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。
@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中注册插件:
<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
上面的插件将会拦截在 Executor 实例中所有的 “update” 方法调用, 这里的 Executor 是负责执行低层映射语句的内部对象。
5.6 environments环境配置
• MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置。
• 每种环境使用一个environment标签进行配置并指定唯一标识符。
• 可以通过environments标签中的default属性指定一个环境的标识符来快速的切换环境。
5.6.1 environment 指定具体环境
• id:指定当前环境的唯一标识
• transactionManager、和dataSource都必须有
<environments default="development">
<environment id="development">
<!--事务管理器-->
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
transactionManager:
• type: JDBC | MANAGED | 自定义
– JDBC:使用了 JDBC 的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围。JdbcTransactionFactory
– MANAGED:不提交或回滚一个连接、让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。ManagedTransactionFactory
– 自定义:实现TransactionFactory接口,type=全类名/别名
dataSource:
• type: UNPOOLED | POOLED | JNDI | 自定义
– UNPOOLED:不使用连接池,UnpooledDataSourceFactory
– POOLED:使用连接池, PooledDataSourceFactory
– JNDI: 在EJB 或应用服务器这类容器中查找指定的数据源
– 自定义:实现DataSourceFactory接口,定义数据源的获取方式。
• 实际开发中我们使用Spring管理数据源,并进行事务控制的配置来覆盖上述配置
5.7 databaseIdProvider 数据库厂商标识
MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。
为支持多厂商特性只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:
<databaseIdProvider type="DB_VENDOR" />
DB_VENDOR 对应的 databaseIdProvider 实现会将 databaseId 设置为 DatabaseMetaData#getDatabaseProductName() 返回的字符串。 由于通常情况下这些字符串都非常长而且相同产品的不同版本会返回不同的值,所以你可能想通过设置属性别名来使其变短,如下:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
• Type: DB_VENDOR– 使用MyBatis提供的VendorDatabaseIdProvider解析数据库厂商标识。也可以实现DatabaseIdProvider接口来自定义。
• Property-name:数据库厂商标识
• Property-value:为标识起一个别名,方便SQL语句使用databaseId属性引用
<select id="selectById" resultType="com.mybatis.pojo.Employee" databaseId="mysql">
select id,last_name,age,addr from t_employee where id = #{id}
</select>
• MyBatis匹配规则如下:
– 1、如果没有配置databaseIdProvider标签,那么databaseId=null
– 2、如果配置了databaseIdProvider标签,使用标签配置的name去匹配数据库信息,匹配上设置databaseId=配置指定的值,否则依旧为null
– 3、如果databaseId不为null,他只会找到配置databaseId的sql语句
– 4、MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库databaseId 属性的所有语句。如果同时找到带有 databaseId 和不带databaseId 的相同语句,则后者会被舍弃。
5.8 mappers 映射器
可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等方式是告诉 MyBatis 到哪里去找映射文件。
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL)/针对网络路径和磁盘路径 -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
注意:这种包扫描package的方式,一定要保证mapper接口和mapper.xml文件在同样的包路径下。
这些配置会告诉了 MyBatis 去哪里找映射文件,剩下的细节就应该是每个 SQL 映射文件了,也就是接下来我们要讨论的。