文章目录
重新认识Mybatis
Mybatis是解决数据
持久化
的框架,采用ORM
思想解决实体和数据库映射的问题,对jdbc进行了封装。可以通过简单的xml配置或注解来配置和映射原始类型,接口和pojo类为数据库中的记录。
SqlSessionFactory
每个基于Mybatis的应用都是以一个SqlSessionFactory
的实例
为核心的。
SqlSessionFactory一旦创建就应该在运行期间一直存在,不需要重新创建实例。多次创建SqlSessionFactory被视为一种
坏习惯
。因此SqlSessionFactory最佳的作用域是应用作用域
,所以最简单的就是使用单例模式或静态单例模式创建它。
而SqlSessionFactory实例可以通过SqlSessionFactoryBuilder 获得
SqlSessionFactoryBuilder
SqlSessionFactoryBuilder 这个类被使用后应该
丢弃
,它的最佳作用域是方法作用域
,可以用它创建多个
SqlSessionFactory实例,事后应该释放该类资源
获得SqlSessionFactory的两类方式
- 从
XML
文件构建SqlSessionFactory
在Resources配置文件根路径下新建XML文件使用输入流加载配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
XML文件配置了有关Mybatis的核心设置信息,如数据源,事务管理器,mapper映射文件等
- 使用
Java
代码获得SqlSessionFactory
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(YourMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
SqlSession
SqlSession是
线程不安全
的,它不能被共享。因此创建它时的最佳作用域是请求或方法作用域
中,不能再类的静态区或实例变量创建它。在Web框架中,将SqlSession放入请求作用域中,确保获取响应后,立即关闭它。
通过SqlSessionFactory实例获取SqlSession实例
try (SqlSession session = sqlSessionFactory.openSession()) {
YourMapper mapper = session.getMapper(YourMapper.class);
Blog blog = mapper.selectBlog(100);
}
映射器实例
映射器实例也就是
Mapper接口
,通过SqlSession实例获得,如上述代码中的YourMapper接口。该实例的最佳作用域是方法作用域
,使用完毕即可关闭资源
Mybatis的XML配置文件
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
属性(properties)
属性可以在配置文件外部
配置,也可以在properties下的property标签内
配置
<properties resource="config.properties">
<property name="username" value="root"/>
<property name="password" value="root"/>
</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会在配置文件下的peopertiy标签内寻找值,driver和url会在外部配置文件config.properties中寻找值。
倘若两处都定义了相同的属性,外部配置文件的属性值会覆盖properties标签内的属性值。
从Mybatis3.4.2开始,可以为属性配置默认值:
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${username:root1}"/> <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'root1' -->
</dataSource>
要启用默认值,则须打开:
<properties resource="config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- 启用默认值特性 -->
</properties>
倘若定义的属性名字中带有:
,比如user:name,那么在使用默认值的时候会有两个:,这种情况不被允许,必须将默认值的符号:
指定为其他符号
<properties resource="config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="!"/> <!-- 修改默认值的分隔符 -->
</properties>
设置(settings)
这些设置将会影响Mybatis运行时的行为,这里列举部分
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局开启或关闭缓存 | true|false | true |
lazyLoadingEnabled | 全局开启或关闭延迟加载 | true|false | false |
useGeneratedKeys | 允许JDBC自动生成主键 | true|false | false |
autoMappingBehavior | 如何自动映射属性字段,NONE:关闭自动映射;PARTIAL:只映射没有嵌套的字段;FULL:自动映射任何复杂的结果 | NONE|PARTIAL|FULL | PARTIAL |
defaultExecutorType | 配置执行器,SIMPLE:普通;REUSE:重用预处理的执行器;BATCH:不仅重用预处理,还支持批量更新 | SIMPLE|REUSE|BATCH | SIMPLE |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射 | true|false | false |
localCacheScope | 默认SESSION:缓存一个会话内的所有查询;STATEMENT:相同的SqlSession内不同查询不会缓存 | SESSION|STATEMENT | SESSION |
logImpl | 指定Mybatis所用的日志实现,未指定自动查找 | SLF4J|LOG4J|等 | 未设置 |
一个完整的settings如下:
<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)
为Java类型定义另一个简单的名字,降低冗余的全限定名称
<typeAliases>
<typeAlias alias="Book" type="com.domain.Book"/>
</typeAliases>
也可以定义一个包,该包下的所有bean用上别名
<typeAliases>
<package name="com.domain"/>
</typeAliases>
若是该包下bean内定义了注解@Alias,则使用该注解定义的别名
否则将该类名首字母小写作为别名
类型处理器(typeHandlers)
Mybatis从数据库中取出结果,会用到类型处理器将获取到的值转换为Java类型
Mybatis提供许多默认的类型处理器,当然也可以自建类型处理器:例如自建 Java类型的String与JDBC的DATE类型转换处理器
@MappedJdbcTypes(JdbcType.DATE)
public class ExampleTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
}
在XML配置文件中开启类型处理器支持
<typeHandlers>
<typeHandler handler="com.utils.ExampleTypeHandler"/>
</typeHandlers>
这样当我们从数据库取出DATE类型的结果时,会通过该类型处理器转换为Java的String类型
对象工厂(objectFactory)
Mybatis运行前会解析配置文件,如果配置了自定义的对象工厂,那么创建对象实例时会使用自定义对象工厂,否则使用默认工厂
DefaultObjectFactory
。当我们想要将对象交给自定义工厂管理,并且自定义属性供对象使用时,便可以创建自定义对象工厂。
public class ExampleObjectFactory extends DefaultObjectFactory {
@Override
public Object create(Class type) {
System.out.println("自定义的对象工厂");
return super.create(type);
}
@Override
public void setProperties(Properties properties) {
Iterator iterator = properties.keySet().iterator();
while (iterator.hasNext()){
String keyValue = String.valueOf(iterator.next());
System.out.println(properties.getProperty(keyValue));
}
super.setProperties(properties);
}
@Override
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}
}
利用Mybatis的对象工厂或继承它自建工厂去管理bean感觉这种事Spring已经可以帮我们做了
环境配置(environments)
Mybatis可以支持连接多个数据库,每一个数据库对应一个SqlSessionFactory。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
至于事务管理器和数据源,连接池等交给Spring去做
映射器(mappers)
配置好数据库环境,接下来要做的事情就是Sql语句
了,Mybatis该去哪找Sql语句呢?无论是注解形式还是XML形式,Mybatis都需要知道注解或XML在哪里,那么映射器就是解决这件事情的,由它带Mybatis去找到Sql语句。
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/YourMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.YourMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
以上是Mybatis的XML配置文件,由这些设置可以实现Mybatis不同的运行状态。
下篇记录Mybatis详细的XML映射文件及动态SQL等