Mybatis配置部分解读
再次强烈建议大家看 Myabtis的配置中文文档本文以及所有关于mybatis的文章,基本内容全部是mybatis3文档的,只是我这里按照自己的脑回路重新梳理了一下,按照自己的需要做了一些侧重的标记。
一.属性(properties)
这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。例如:
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
然后其中的属性就可以在整个配置文件中被用${}来替换需要动态配置的属性值。比如:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
这个例子中的 username 和 password 将会由 properties 元素中设置的相应值来替换。 driver 和 url 属性将会由 config.properties 文件中对应的值来替换。这样就为配置提供了诸多灵活选择。
属性也可以被传递到 SqlSessionFactoryBuilder.build()方法中。例如
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
// ... 或者 ...
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);
如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:
- 在 properties 元素体内指定的属性首先被读取。
- 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的是 properties 属性中指定的属性。
从 MyBatis 3.4.2 开始,你可以为占位符指定一个默认值。例如:
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${username:ut_user}"/> <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' -->
</dataSource>
这个特性默认是关闭的。如果你想为占位符指定一个默认值, 你应该添加一个指定的属性来开启这个特性。例如:
<properties resource="org/mybatis/example/config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- 启用默认值特性 -->
</properties>
提示
如果你已经使用 ":" 作为属性的键(如:db:username
) ,或者你已经在 SQL 定义中使用 OGNL 表达式的三元运算符(如:${tableName != null ? tableName : 'global_constants'}
),你应该通过设置特定的属性来修改分隔键名和默认值的字符。例如:
<properties resource="org/mybatis/example/config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> <!-- 修改默认值的分隔符 -->
</properties>
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${db:username?:ut_user}"/>
</dataSource>
二. 类型处理器(typeHandlers)
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型
。默认的类型处理器
我们也可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型。
具体做法为:
- 实现 org.apache.ibatis.type.TypeHandler 接口
- 继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个 JDBC 类型。
比如:
public class MyTypeHandler extends BaseTypeHandler<String> {
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
// 设置 String 类型的参数的时候调用,Java类型到JDBC类型
// 注意只有在字段上添加typeHandler属性才会生效
// insertBlog name字段
System.out.println("---------------setNonNullParameter1:"+parameter);
ps.setString(i, parameter);
}
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
// 根据列名获取 String 类型的参数的时候调用,JDBC类型到java类型
// 注意只有在字段上添加typeHandler属性才会生效
System.out.println("---------------getNullableResult1:"+columnName);
return rs.getString(columnName);
}
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
// 根据下标获取 String 类型的参数的时候调用
System.out.println("---------------getNullableResult2:"+columnIndex);
return rs.getString(columnIndex);
}
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
System.out.println("---------------getNullableResult3:");
return cs.getString(columnIndex);
}
}
当然我们必须在mybatis.config的configuration里配置
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.mybatis.example.MyTypeHandler "/>
</typeHandlers>
三.类型别名(typeAliases)
类型别名是为 Java 类型设置一个短的名字。 它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
</typeAliases>
当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
<package name="domain.blog"/>
</typeAliases
每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:
@Alias("author")
public class Author {
...
}
四.映射器(mappers)
mappers负责定义 SQL 映射语句了。 但是首先我们需要告诉 MyBatis 到哪里去找到这些语句。 Java 在自动查找这方面没有提供一个很好的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等。例如:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
这些配置会告诉了 MyBatis 去哪里找映射文件
关于mapper.xml
五. 对象工厂(objectFactory)
MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类
,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现.
比如,我们可以自定义一个类继承DefaultObjectFactory,在此基础上做扩展.
如下.
// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
@Override
public Object create(Class type) {
System.out.println("创建对象方法:" + type);
if (type.equals(Blog.class)) {
Blog blog = (Blog) super.create(type);
blog.setName("object factory");
blog.setBid(1111);
blog.setAuthorId(2222);
return blog;
}
Object result = super.create(type);
return result;
}
这样的效果就在于,我们把返回结果为Blog.class的对象全部都赋了自己的默认值.
类似于啥呢?我们在配置Netty心跳机制的时候需要先添加一个事件机制处理器,然后我们会在事件机制中判断是不是心跳事件机制,如果是心跳事件机制我们再进行处理.
当然所有自定义配置,必须在mybatis.xml里进行声明,使其在创建sqlsession的整套流程中可以起作用.
<!-- mybatis-config.xml -->
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
<property name="someProperty" value="100"/>
</objectFactory>
ObjectFactory 接口 很简单,它包含两个创建用的方法
- 一个是处理默认构造方法的
- 另外一个是处理带参数的构造方法的。
最后,setProperties 方法可以被用来配置 ObjectFactory,在初始化你的 ObjectFactory 实例后, objectFactory 元素体中定义的属性会被传递给 setProperties 方法。
// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
public Object create(Class type) {
return super.create(type);
}
public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {
return super.create(type, constructorArgTypes, constructorArgs);
}
public void setProperties(Properties properties) {
super.setProperties(properties);
}
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}}
六. 环境配置(environments)
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中 使用相同的 SQL 映射。有许多类似的使用场景。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:
每个数据库对应一个 SqlSessionFactory 实例
为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。可以接受环境配置的两个方法签名是:
SqlSessionFactory factory =
new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory =
new SqlSessionFactoryBuilder().build(reader, environment, properties);
如果忽略了环境参数,那么默认环境将会被加载,如下所示:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
另外这里还有定义些
如:
事务管理器(transactionManager)
数据源(dataSource)
一. 关于连接池
我们mybatis肯定要配置连接池,实现连接的自动管理,减少开销的.
在 Mybatis 的 SqlMapConfig.xml
配置文件中,通过<dataSource type=”pooled”>
来实现 Mybatis 中连接池的配置。
在 Mybatis 中我们将它的数据源 dataSource 分为以下几类:
二. Mybatis 将它自己的数据源分为三类:
- UNPOOLED 不使用连接池的数据源
- POOLED 使用连接池的数据源
- JNDI 使用 JNDI 实现的数据源
在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据库连接,也就是我们所说的连接池技术)。
对比pooled和unpooled,发现第一个关闭了连接并且返回了,第二个没有返回对于几种连接池相应地,MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource
,PooledDataSource
类来表示 UNPOOLED、POOLED 类型的数据源。