mybatis 工作原理
几个核心类
参见:
SqlSessionFactory
mybatis 应用以一个 sqlSessionFactory 实例为核心,即一个应用中有一个单例 SqlSessionFactory,所以数据库 session 都从这里获得。
SqlSessionFactory 可以通过 SqlSessionFactoryBuilder 获得,builder 负责从 xml 配置或 java configuration 类获得。xml (或相应的 java configuration 类) 配置了 datasource(数据库连接信息)、mappers 等信息
SqlSessionFactoryBuilder
它主要就是用来获取 SqlSessionFactory,可以从 xml 或 Java Configuration 类加载配置并构建。提供如下几种方式来获取(参见java api):
1  | // 从 xml 获取,其中配置了 environment,datasource,mappers  | 
SqlSessionFactoryBuilder 只是为了创建 SqlSessionFactory,创建完成就可以丢弃 builder 了。所以一般它的生命周期是方法级,是其中的一个局部变量
使用 xml
先配置一个 config.xml:
1  | 
  | 
上边的配置中,environments 配置的是各个环境下的数据库配置。每个环境下,都可以配置 TransactionManager、datasource 等,连接数据库、包括操作数据库的 driver 等信息都是在这里配置的)。
${driver} 这种写法是用的 property。property 可以直接在这个 xml 中配置(使用 <properties> 标签),也是 java 中的 System.getProperties() 中的 property,还可以是在 SqlSessionBuilder 中传递的 props 参数。
构建 SqlSessionFactory:
1  | String resource = "org/mybatis/example/mybatis-config.xml";  | 
使用 java Configuration 类
1  | DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();  | 
SqlSession
SqlSession 是执行 sql 命令的接口:
1  | SqlSession session = sqlSessionFactory.openSession();  | 
SqlSession 可以执行所有的 sql 命令、做事务提交、回滚、获取 Mapper 实例等,非常强大。SqlSession 也是方法作用域级别的,并且必须被正确关闭:
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理作用域中,比如 Servlet 架构中的 HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的作用域中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。下面的示例就是一个确保 SqlSession 关闭的标准模式:
 1
2
3
4
5
6 SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}
Mapper
Mapper 是资源和数据库实例的映射,提供了相关操作来做转换。可以用两种方式写:xml 或 annotation。
mapper 实例从 SqlSession 获得,所以生命周期和 SqlSession 相同。
xml
1  | 
  | 
访问:
1  | Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);  | 
当然,我们希望通过 java 接口来调用这些方法,所以可以写相应的 mapper 接口 ,只要保证 namespace 是一致的即可。namespace 是实现接口绑定的方式。mybatis 基于命名空间的命名解析规则如下:
- 完全限定名(比如“com.mypackage.MyMapper.selectAllThings”)将被直接查找并且找到即用。
 - 短名称(比如“selectAllThings”)如果全局唯一也可以作为一个单独的引用。如果不唯一,有两个或两个以上的相同名称(比如“com.foo.selectAllThings ”和“com.bar.selectAllThings”),那么使用时就会收到错误报告说短名称是不唯一的,这种情况下就必须使用完全限定名。
 
一旦绑定了接口,就可以用如下方式访问 mapper 方法了:
1  | BlogMapper mapper = session.getMapper(BlogMapper.class);  | 
annotation
也可以不依赖于 xml,直接在 mapper 接口上通过 annotation 定义 sql:
1  | package org.mybatis.example;  | 
annotation 可能更简洁一些,但是 mybatis 目前还是 xml 更强大。大家可以依据需求自由的在两种方式之间切换,mybatis 会自己检测。
由于 Java 注解的一些限制加之某些 MyBatis 映射的复杂性,XML 映射对于大多数高级映射(比如:嵌套 Join 映射)来说仍然是必须的。有鉴于此,如果存在一个对等的 XML 配置文件的话,MyBatis 会自动查找并加载它(这种情况下, BlogMapper.xml 将会基于类路径和 BlogMapper.class 的类名被加载进来)