我们先来看看Mybatis官方对于Mybatis的简介
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old JavaObjects,普通老式 Java 对象)为数据库中的记录。
从这段可以看出Mybatis封装了JDBC并使用XML配置来让我们操作数据库,那么他的执行流程是怎样的呢,
我们先从一个简单的例子来分析他的执行流程
@Test
public void sqlSessionFactoryByXML() throws IOException {
// 路径
String resource = "mybatis-test.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//SqlSessionFactoryBuilder.build方法会自动关闭流
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"test");
try (SqlSession session = sqlSessionFactory.openSession();) {
TbItemMapper mapper = session.getMapper(TbItemMapper.class);
TbUserMapper usermapper = session.getMapper(TbUserMapper.class);
TbUser user = usermapper.selectByPrimaryKey((long) 7);
TbItem item = mapper.selectByPrimaryKey((long) 562379);
System.out.println(user);
System.out.println(item);
}
}
重要的与数据库交互对象SqlSession
SqlSession是Mybatis提供给用户与数据库交互的重要对象,我们可以调用SqlSession的getMapper方法来取得
Mapper代理类,而SqlSession由SqlSessionFactory构建,SqlSessionFactory由SqlSessionFactoryBuilder构建而来
我们先看SqlSessionFactoryBuilder以及SqlSessionFactory源码来分析SqlSession是怎么样创建的
SqlSessionFactoryBuilder的主要方法
/**
* 根据字节流构建SqlSessionFactroy
* */
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//调用重载的方法build(Configuration config)
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close(); //流会关闭
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
/**
* 根据字节流构建SqlSessionFactroy
* */
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
/**
* new 一个DefaultSqlSessionFactory
* @param config mybatis核心配置文件转换成的类
* @return
*/
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
SqlSessionFactoryBuilder读取了核心配置文件一般名字是Mybatis.xml 用XMLConfigBuilder 类来构建了Configuration ,Configuration是一个重要的对象,它封装了Mybatis.xml的所以配置文件,接着直接
new 了一个DefaultSqlSessionFactory 并返回
DefaultSqlSessionFactory
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
public SqlSession openSession(Connection connection) {
return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
boolean autoCommit) {
Transaction tx = null;
try {
//取得核心配置文件所映射的Environment类
final Environment environment = configuration.getEnvironment();
//根据环境的配置如取得事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//configuration 取得执行器 是什么类型的执行器则根据execType来判断,这里注意cacheExecutor只是一个装饰器,如果需要二级缓存,就会装饰相应的Executor
//核心配置文件中的插件也将改变Executor的行为 : Executor的分析看executor包下
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();
}
}
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException e) {
// Failover to true, as most poor drivers
// or databases won't support transactions
autoCommit = true;
}
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
final Transaction tx = transactionFactory.newTransaction(connection);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
/**
* 如果 环境节点配置了事务类型则跟据配置返回TransactionFactory,如果没有配置放回ManagedTransactionFactory
* */
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
DefaultSqlSessionFactory 的两个核心的取SqlSession 的方法openSessionFromDataSource,openSessionFromConnection。两者的逻辑大致相似,都new 了一个DefaultSqlSession并把Configuration,Executor,是否自动commit等属性注入到了DefaultSqlSession,不同的是openSessionFromDataSource接受TransactionIsolationLevel level boolean autoCommit,
根据这些配置构建事务,而openSessionFromConnection 接受一个Connection来构建事务,其实原理是一样的,事务封装了Connection,事务工厂的newTransaction方法根据接收的TransactionIsolationLevel ,autoCommit构建Connection并注入到事务中返回
总结
以上大致就是取得一个SqlSession的流程,SqlSessionFactoryBuilder通过XMLConfigBuilder得到Configuration注入到DefaultSqlSessionFactory中并返回DefaultSqlSessionFactory实例,DefaultSqlSessionFactory根据Configuration生成不同的执行器Executor,事务Transaction注入到DefaultSqlSession中并返回该实例,这样我们就得到了一个SqlSession。
对于Executor,Transaction我们会在以后的章节中分析
[下一篇]: Mybais 源码分析二 SqlSession