SqlSession源码分析
前言
在Mybatis中的核心操作是:SqlSession实例对象是Mybatis中用来执行sql语句的核心类。sql语句在Mybatis中的核心执行简化后逻辑如下(好好看注释内容):
//1.通过mybatis-config.xml来获取一个输入流
InputStream inputStream=Resources.getResourceAsStream("mybatis-config.xml")
//2.通过该输入流来建造一个SqlSessionFactory对象factory,
//注意:这里使用了匿名构造对象,没有具体的引用指向它,因此只能用一次,用完后垃圾回收器会自动调用Fianlization函数把它给回收了
factory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过factory创建一个SqlSession对象
SqlSession sqlSession = factory.openSession();
//4.把SqlSession对象放入ThreadLocal变量中(将不会被其他线程所获取)
private static ThreadLocal<SqlSession> local = new ThreadLocal<>();
local.set(sqlSession);
//5.可通过get方法来获取本线程中的sqlSession。
SqlSession session=local.get()
一.这三个重要类的生命周期和作用域
【SqlSessionFactoryBuilder生命周期】:在创建了SqlSessionFactory创建了之后将失效,因此我们将它放在静态代码块中,整个程序中,只执行一次。
【SqlSessionFactory生命周期】:可以看做一个数据库连接池。SqlSessionFactory一个程序只需要有一个就行,一旦创建后就会一直存在(也可以创建多个,但是会引起资源的浪费)。最好使用单例模式或者静态单例模式
【SqlSession生命周期】:可以看做是连接到连接池的一个请求(需要开启和关闭请求)。每个线程都要有一个SqlSession,且用完要赶紧关闭不然会造成资源浪费。它是非线程安全的
二.源码分析
1.SqlSessionFactoryBuilder分析(还需要去读XMLConfigBuilder的parse源码,很难,待完成)
SqlSessionFactoryBuilder是专门用来创建SqlSessionFactory,其内部全是用来创建SqlSessionFactory的Build()函数的多个重载方法。在创建SqlSessionFactory的创建过程中,会使用到XMLConfigBuilder的parse函数。XMLConfigBuilder的parse,它的作用是把MyBatis的XML及相关配置解析出来,然后保存到 Configuration中
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.apache.ibatis.session;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
import org.apache.ibatis.exceptions.ExceptionFactory;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
public class SqlSessionFactoryBuilder {
public SqlSessionFactoryBuilder() {
}
public SqlSessionFactory build(Reader reader) {
return this.build((Reader)reader, (String)null, (Properties)null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return this.build((Reader)reader, environment, (Properties)null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return this.build((Reader)reader, (String)null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException var13) {
}
}
return var5;
}
public SqlSessionFactory build(InputStream inputStream) {
return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return this.build((InputStream)inputStream, environment, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return this.build((InputStream)inputStream, (String)null, properties);
}
//以下这个函数是SqlSessionFactoryBuilder的核心代码。但是会跳转到XMLConfigBuilder中去,由于看不懂其源码,我就先不讲了,以后再说
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
}
}
return var5;
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
2.SqlSessionFactory源码分析
SqlSessionFactory是SqlSession的抽象工厂,是一个接口,其内部所有函数都是用来构造SqlSession的openSession抽象函数。这样也会引出一个问题,既然SqlSessionFactory是一个接口,那它是怎么产生的SqlSession类的对象的呢?实际上,SqlSessionFactoryBuilder通过builder方法会产生一个SqlSessionFactory接口的实现类,该类中已经实现了openSession方法了。
package org.apache.ibatis.session;
import java.sql.Connection;
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean var1);
SqlSession openSession(Connection var1);
SqlSession openSession(TransactionIsolationLevel var1);
SqlSession openSession(ExecutorType var1);
SqlSession openSession(ExecutorType var1, boolean var2);
SqlSession openSession(ExecutorType var1, TransactionIsolationLevel var2);
SqlSession openSession(ExecutorType var1, Connection var2);
Configuration getConfiguration();
}
3.SqlSession源码分析
SqlSession是一个用来执行sql语句的接口,其内部几乎所有的函数都是与sql语句相关的。但是
通过查看SqlSession的源码(下面会查看),我们会发现SqlSession中除了是增删改查,提交和回滚操作外,还有几个重要的方法,它们的作用我写在了注释中了。
package org.apache.ibatis.session;
import java.io.Closeable;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.BatchResult;
public interface SqlSession extends Closeable {
<T> T selectOne(String var1);
<T> T selectOne(String var1, Object var2);
<E> List<E> selectList(String var1);
<E> List<E> selectList(String var1, Object var2);
<E> List<E> selectList(String var1, Object var2, RowBounds var3);
<K, V> Map<K, V> selectMap(String var1, String var2);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);
<T> Cursor<T> selectCursor(String var1);
<T> Cursor<T> selectCursor(String var1, Object var2);
<T> Cursor<T> selectCursor(String var1, Object var2, RowBounds var3);
void select(String var1, Object var2, ResultHandler var3);
void select(String var1, ResultHandler var2);
void select(String var1, Object var2, RowBounds var3, ResultHandler var4);
int insert(String var1);
int insert(String var1, Object var2);
int update(String var1);
int update(String var1, Object var2);
int delete(String var1);
int delete(String var1, Object var2);
void commit();//提交操作。由于Mybatis对数据库的操作是在缓存中进行的,如果不提交,讲不会对数据库有任何影响。
void commit(boolean var1);
void rollback();//回滚,使得所有未提交的sqlSession操作的撤回
void rollback(boolean var1);
List<BatchResult> flushStatements();
void close();//关闭SqlSession
void clearCache();//清除缓存,Mybatis有三级缓存机制。
Configuration getConfiguration();//?
<T> T getMapper(Class<T> var1);//
Connection getConnection();//?
}