之前看了看mybatis的日志模块源码,对mybatsi的运行流程也有了一些兴趣,下面我们从sqlsessionFactory开始,看看mybatis是如何实现orm查询的。
一般初始化sqlSessionFactory的代码如下:mybatis的config文件通过Resources类中的静态方法传入,可以接受Reader或者inputStream。然后通过sqlSessionFactoryBuilder构造sqlSessionFactory,然后拿到sqlsession,通过getMapper方法传入dao接口或者通过selectList等方法传入dao接口路径和DO类。
public static void main(String[] args) throws IOException {
SqlSessionFactory builder = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("resources path"));
SqlSession sqlSession = builder.openSession();
QueryDao mapper = sqlSession.getMapper(QueryDao.class);
// Entry entry = new Entry();
// List<Object> list = sqlSession.selectList("mapping.namespace",entry);
List list = mapper.queryList();
}
static class Entry{
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
interface QueryDao {
List queryList();
}
把以上的过程稍微拆分一下:
//解析xml
InputStream resourceAsStream = Resources.getResourceAsStream(resources);
XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(resourceAsStream);
Configuration parse = xmlConfigBuilder.parse();
//返回configure
sqlSessionFactory = new SqlSessionFactoryBuilder().build(parse);
SqlSession sqlSession = sqlSessionFactory.openSession();
//getMapper
StudentDAO mapper = sqlSession.getMapper(StudentDAO.class);
Student student = mapper.showStudent(2276189);
1.通过ClassLoader获取配置文件输入流
2.构造XMLConfigBuilder对象,用于解析xml文件
3.xml解析,把配置文件中的内容映射到Configuration对象中
4.通过SqlSessionFactoryBuilder传入一个configuration对象构建SqlSessionFactory
5.openSession开启会话
6.拿到mapper代理对象
前三布没什么好说的,无论什么框架都要经过xml解析,但解析的细节有的是自己实现的,有的引用了别的开源框架,mybatis用的应该是封装后的SAX。然后parse,把一些必要的属性和对象初始化。
第四部也没什么好说的,一个工厂模式,把sax解析后的confguration对象set到SqlSessionFactory里了。我们主要看openSession和getMapper。openSession代码如下:
DefaultSqlSessionFactory.openSessionFromDataSource
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
exectype是个枚举类,有三种状态,SIMPLE, REUSE, BATCH,分别是基础类型,重用(缓存过),批量,默认使用SIMPLE,后面的事务隔离等级和自动提交为null。至于configuration.getEnvironment(),顾名思义,对应的是conf文件中的Environment标签及内容。然后通过事务工厂新建个事务,如果你的mybatis没和spring整合,这个事务会使用默认的mybatis包装后的jdbc事务。然后是新建一个Executor执行器,代码如下:
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
如果第一次创建,则会使用simpleExecutor,这个执行器会被缓存的executor包装起来。