文章目录
前言
在MyBatis中其实最核心的应该是两个配置文件,一个全局配置文件,一个映射文件。只要把这两个文件弄清楚,对于MyBatis的使用就掌握了大部分,本文介绍下这两个配置文件。
全局配置文件
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
configuration
configuration是整个配置文件的根标签,实际上也对应着MyBatis里面最重要的配置类Configuration。它贯穿MyBatis执行流程的每一个环节。
properties
第一个一级标签是properties,用来配置参数信息,比如最常见的数据库连接信息。
为了避免直接把参数写死在xml配置文件中,我们可以把这些参数单独放在properties文件中,用properties标签引入进来,然后在xml配置文件中用${}引用就可以了。可以用resource引用应用里面的相对路径,也可以用url指定本地服务器或者网络的绝对路径。
<?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"/><!-- 单独使用时配置成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>
</configuration>
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是类型的别名,主要用来简化类名全路径的拼写。比如参数类型和返回值类型都可能会用到我们的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);
registerAlias("ResultSet", ResultSet.class);
}
TypeHandler
由于Java类型和数据库的JDBC类型不是一一对应的(比如String与varchar、char、text),所以把Java对象转换为数据库的值,和把数据库的值转换成Java对象,需要经过一定的转换,这两个方向的转换就要用到TypeHandler。
我们可以自定义一个TypeHandler来帮助我们简单的处理数据,比如查询的结果的字段如果是一个字符串,且值为"zhangsan"就修饰下这个信息
/**
* 自定义的类型处理器
* 处理的字段如果是 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.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);
}
ObjectFactory有一个默认的实现类DefaultObjectFactory。创建对象的方法最终都调用了instantiateClass(),这里面能看到反射的代码。
默认情况下,所有的对象都是由DefaultObjectFactory创建。
/**
*
* 自定义ObjectFactory,通过反射的方式实例化对象
* 一种是无参构造函数,一种是有参构造函数——第一个方法调用了第二个方法
*/
public class MyObjectFactory extends DefaultObjectFactory {
@Override
public Object create(Class type) {
System.out.println("创建对象方法:" + type);
if (type.equals(User.class)) {
User blog = (User) super.create(type);
blog.setUserName("object factory");
blog.setId(1111);
blog.setRealName("张三");
return blog;
}
Object result = super.create(type);
return result;
}
}
plugins
插件是MyBatis的一个很强大的机制。跟很多其他的框架一样,MyBatis预留了插件的接口,让MyBatis更容易扩展。详细内容
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
<mappers>标签配置的是映射器,也就是Mapper.xml的路径。这里配置的目的是让MyBatis在启动的时候去扫描这些映射器,创建映射关系。
有四种指定Mapper文件的方式:
-
使用相对于类路径的资源引用(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
– 映射查询语句。
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">