在MyBatis中我们发现其实他最核心的应该是那两个配置文件,一个全局配置文件,一个映射文件。 我们只要把这两个文件弄清楚,其实对于MyBatis的使用就掌握了大部分。接下来我们详细的给大家来 介绍下这两个配置文件。
全局配置文件
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如 下:
标签 | 描述 |
configuration | 配置 |
properties | 属性 |
settings | 设置 |
typeAliases | 类型别名 |
typeHandlers | 类型处理器 |
objectFactory | 对象工厂 |
plugins | 插件 |
environments | 环境配置 |
environment | 环境变量 |
transactionManager | 事务管理器 |
dataSource | 数据源 |
databaseIdProvider | 数据库厂商标识 |
mappers | 映射器 |
configuration
configuration是整个配置文件的根标签,实际上也对应着MyBatis里面最重要的配置类Configuration。它贯穿MyBatis执行流程的每一个环节。我们打开这个类看一下,这里面有很多的属性,跟其他的子标签也能对应上。
properties
第一个一级标签是properties,用来配置参数信息,比如最常见的数据库连接信息。为了避免直接把参数写死在xml配置文件中,我们可以把这些参数单独放在properties文件中,用 properties标签引入进来,然后在xml配置文件中用${}引用就可以了。可以用resource引用应用里面的 相对路径,也可以用url指定本地服务器或者网络的绝对路径。
settings
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各 项设置的含义、默认值等。
<settings>
<!-- 打印查询语句 -->
<setting name="logImpl" value="STDOUT_LOGGING" />
<!-- 控制全局缓存(二级缓存),默认 true-->
<setting name="cacheEnabled" value="false"/>
<!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过select标签
的 fetchType来覆盖-->
<setting name="aggressiveLazyLoading" value="true"/>
<!-- Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST -->
<!--<setting name="proxyFactory" value="CGLIB" />-->
<!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效 -->
<!--
<setting name="localCacheScope" value="STATEMENT"/>
-->
<setting name="localCacheScope" value="SESSION"/>
</settings>
typeAliases
TypeAlias是类型的别名,跟Linux系统里面的alias一样,主要用来简化类名全路径的拼写。比如我 们的参数类型和返回值类型都可能会用到我们的Bean,如果每个地方都配置全路径的话,那么内容就比 较多,还可能会写错。 我们可以为自己的Bean创建别名,既可以指定单个类,也可以指定一个package,自动转换。
<typeAliases>
<typeAlias alias="user" type="com.domain.User" />
</typeAliases>
然后在使用的时候我们就可以简化了
MyBatis里面有很多系统预先定义好的类型别名,在TypeAliasRegistry中。所以可以用string代替 java.lang.String。
public TypeAliasRegistry() {
registerAlias("string", String.class);
registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);
registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);
registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);
registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);
registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);
registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);
}
TypeHandler
由于java类型和数据库的JDBC类型不是一一对应的(比如String与Varchar、char、text),所以我们把Java对象转换为数据库的值,和把数据库的值转换成Java对象,需要经过一定的转换,这两个方向的转换就要用到TypeHandler。
当参数类型和返回值是一个对象的时候,没有做任何配置的情况下,为什么对象里面的一个String属性可以转换成数据库里面的varchar字段?
这是因为mybatis已经内置了很多TypeHandler(在type包下),他们全都注册在TypeHandlerRegistry中,他们都继承了抽象类BaseTypeHandler,泛型就是要处理的Java数据类型。
这个也是为什么大部分类型都不需要处理,当我们查询数据和登记数据,做数据类型转换的时候就会自动自动调用对应的TypeHandler方法。
我们可以自定义一个TypeHandler来帮助我们简单的处理数据,比如查询的结果的字段如果是一个字符 串,且值为"zhangsan"就修饰下这个信息
package cloud2.outer.service.impl;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 自定义的类型处理器
* 处理的字段如果是 String类型的话就 且 内容是 zhangsan 拼接个信息
*/
public class MyTypeHandler extends BaseTypeHandler<String> {
/**
* 插入数据的时候回调的方法
* @param ps
* @param i
* @param parameter
* @param jdbcType
* @throws SQLException
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String
parameter, JdbcType jdbcType) throws SQLException {
System.out.println("---------------setNonNullParameter1:"+parameter);
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws
SQLException {
String name = rs.getString(columnName);
if("zhangsan".equals(name)){
return name+"666";
}
return name;
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws
SQLException {
String name = rs.getString(columnIndex);
if("zhangsan".equals(name)){
return name+"666";
}
return name;
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
String name = cs.getString(columnIndex);
if("zhangsan".equals(name)){
return name+"666";
}
return name;
}
}
同时将我们的处理器在全局配置文件中注册下
<typeHandlers>
<typeHandler handler="com.gupaoedu.type.MyTypeHandler"></typeHandler>
</typeHandlers>
objectFactory
当我们把数据库返回的结果集转换为实体类的时候,需要创建对象的实例,由于我们不知道需要处理 的类型是什么,有哪些属性,所以不能用new的方式去创建。只能通过反射来创建。
在MyBatis里面,它提供了一个工厂类的接口,叫做ObjectFactory,专门用来创建对象的实例 (MyBatis封装之后,简化了对象的创建),里面定义了4个方法。
public interface ObjectFactory {
default void setProperties(Properties properties) {
// NOP
}
<T> T create(Class<T> type);
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object>
constructorArgs);
<T> boolean isCollection(Class<T> type);
}
方法 | 作用 |
void setProperties(Properties properties); | 设置参数时调用 |
T create(Class type); | 创建对象(调用无参构造函数) |
T create(Class type, List> constructorArgTypes, List constructorArgs); | 创建对象(调用带参数构造函 数) |
boolean isCollection(Class type) | 判断是否集合 |
ObjectFactory有一个默认的实现类DefaultObjectFactory。创建对象的方法最终都调用了 instantiateClass(),这里面能看到反射的代码。 默认情况下,所有的对象都是由DefaultObjectFactory创建。
plugins
插件是MyBatis的一个很强大的机制。跟很多其他的框架一样,MyBatis预留了插件的接口,让 MyBatis更容易扩展。 mybatis – MyBatis 3 | 配置 具体的插件的原理使用后面的章节会详细介绍。
environments
environments标签用来管理数据库的环境,比如我们可以有开发环境、测试环境、生产环境的数 据库。可以在不同的环境中使用不同的数据库地址或者类型。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/><!-- 单独使用时配置成MANAGED没有事务 -->
<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>
environment
一个environment标签就是一个数据源,代表一个数据库。这里面有两个关键的标签,一个是事务管理器,一个是数据源。
transactionManager
如果配置的是JDBC,则会使用Connection对象的commit()、rollback()、close()管理事务。
如果配置成MANAGED,会把事务交给容器来管理,比如JBOSS,Weblogic。因为我们跑的是本地程序,如果配置成MANAGE不会有任何事务。
如果是Spring + MyBatis,则没有必要配置,因为我们会直接在applicationContext.xml里面配置数据源和事务,覆盖MyBatis的配置。
dataSource
数据源,顾名思义,就是数据的来源,一个数据源就对应一个数据库。在Java里面,它是对数据库 连接的一个抽象。 一般的数据源都会包括连接池管理的功能,所以很多时候也把DataSource直接 称为连接池,准确的说 法应该是:带连接池功能的数据源.
mappers
标签配置的是映射器,也就是Mapper.xml的路径。这里配置的目的是让MyBatis在启动 的时候去扫描这些映射器,创建映射关系。 我们有四种指定Mapper文件的方式: mybatis – MyBatis 3 | 配置
- 使用相对于类路径的资源引用(resource)
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
- 使用完全限定资源定位符(绝对路径)(URL)
<mappers>
<mapper resource="file:///app/sale/mappers/UserMapper.xml"/>
</mappers>
- 使用映射器接口实现类的完全限定类名
<mappers>
<mapper class="com.mapper.UserMapper"/>
</mappers>
- .将包内的映射器接口实现全部注册为映射器(最常用)
<mappers>
<mapper class="com.mapper"/>
</mappers>
映射文件
Mybatis的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的XML文件就显得相对简单。如果拿它跟具有相同功能的JDBC代码进行对比,你会立即发现省掉了将近95%的代码,Mybatis致力于减少使用成本,让用户能更专注于SQL代码。
SQL映射文件只有很少的几个顶级元素(按照被定义的顺序列出)
标签 | 描述 |
cache | 该命名空间的缓存配置。 |
cache-ref | 引用其它命名空间的缓存配置。 |
resultMap | 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。 |
parameterMap | 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。 |
sql | 可被其它语句引用的可重用语句块。 |
insert | 映射插入语句。 |
update | 映射更新语句。 |
delete | 映射删除语句。 |
select | 映射查询语句。 |
cache
给定命名空间的缓存配置(是否开启二级缓存)。
cache-ref
其他命名空间缓存配置的引用。缓存相关两个标签我们在讲解缓存的时候会详细讲到。
resultMap
是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
<resultMap id="BaseResultMap" type="Employee">
<id column="emp_id" jdbcType="INTEGER" property="empId"/>
<result column="emp_name" jdbcType="VARCHAR" property="empName"/>
<result column="gender" jdbcType="CHAR" property="gender"/>
<result column="email" jdbcType="VARCHAR" property="email"/>
<result column="d_id" jdbcType="INTEGER" property="dId"/>
</resultMap>
sql
可被其他语句引用的可重用语句块。
<sql id="Base_Column_List">
emp_id, emp_name, gender, email, d_id
</sql>
增删改查标签
针对常用的增删改查操作提供的有对应的标签来处理
<insert> – 映射插入语句
<update>–映射更新语句
<delete>–映射删除语句
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
属性 | 描述 |
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType | 将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为MyBatis可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
parameterMap | 用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。 |
resultType | 期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。resultType 和resultMap 之间只能同时使用一个。 |
resultMap | 对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和resultMap 之间只能同时使用一个。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 |
useCache | 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 |
fetchSize | 这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。 |
statementType | 可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。 |
resultOrdered | 这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。这就使得在获取嵌套结果集的时候不至于内存不够用。默认值: false 。 |
resultSets | 这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。 |