一、SqlSessionFactoryBuilder构建
该方法用于创建SqlSessionFactory
,包含下面几种类型的方法,用于创建SqlSessionFactory
-
public SqlSessionFactory build(InputStream inputStream)
-
public SqlSessionFactory build(InputStream inputStream, String environment)
-
public SqlSessionFactory build(InputStream inputStream, Properties properties)
-
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)
-
public SqlSessionFactory build(Configuration config)
-
public SqlSessionFactory build(Reader reader)
inputStream和Reader都表示xml配置文件地址,environment表示是环境,properties表示配置信息
Configuration config 表示最终要构建的对象,xml方式,最终也是在构建Configuration对象,它表示全局配置
XML配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <!-- 配置数据库连接信息 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://xx.xx.xx.xx:3306/table" /> <property name="username" value="root" /> <property name="password" value="123456" /> </dataSource> </environment> </environments> <mappers> <mapper resource="TestMapper.xml"></mapper> </mappers> </configuration>
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); InputStream is = Thread.currentThread().getContextClassLoader() .getResourceAsStream("configuration.xml"); SqlSessionFactory build = builder.build(is); // 读取配置文件并且构建SqlSessionFactory System.out.println(build);
二、SqlSessionFactory获取
通过**SqlSessionFactory build = builder.build(is);**获取到SqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
SessionFactory是工厂,所有的session都是从该对象产生,全局单例。默认的实现对象为DefaultSqlSessionFactory
三、SqlSession获取
在DefaultSqlSessionFactory中有多种获取SqlSession的方式,如下
public SqlSession openSession()
@Override
public SqlSession openSession(boolean autoCommit)
@Override
public SqlSession openSession(ExecutorType execType)
@Override
public SqlSession openSession(TransactionIsolationLevel level)
...
虽然有多种参数的方式,但是最终调用的都是下面这个方法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();
}
}
ExecutorType execType 执行器类型,枚举值
SIMPLE: 默认的执行器, 对每条sql进行预编译->设置参数->执行等操作,默认。
BATCH: 批量执行器, 对相同sql进行一次预编译, 然后设置参数, 最后统一执行操作
REUSE: REUSE 执行器会重用预处理语句(prepared statements)
TransactionIsolationLevel level 事务隔离级别
boolean autoCommit 是否自动提交
其中比较关键的三个步骤是用来获取***数据库连接和事务***的
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
很关键的一步,获取执行器
final Executor executor = configuration.newExecutor(tx, execType);
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;
}
最后组装获取DefaultSqlSession对象
四、获取接口mapper的对象
在进行第一步构建时候,通过配置文件,会将所有的mapper进行注册,Configuration > MapperRegistry > knownMappers
在knownMappers这个map中存储的是MapperProxyFactory对象,该对象保存了mapper接口的基本信息
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
获取mapper对象的过程,实际上就是到knownMappers中获取接口的基本信息MapperProxyFactory,通过该对象使用JDK的代理,创建代理对象
mapperProxyFactory.newInstance(sqlSession);
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); // JDK动态代理
}
五、执行方法
public static void main(String[] args) {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
InputStream is = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("configuration.xml");
SqlSessionFactory build = builder.build(is);
SqlSession sqlSession = build.openSession();
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
Integer count = mapper.count();
System.out.println(count);
}
<mapper namespace="com.mybatistest.mapper.TestMapper">
<select id="count" resultType="int">
select count(1) from person
</select>
</mapper>
1、在调用接口方法时,实际上进入了SqlSession中,在SqlSession中对于数据库操作实际上只有两种,分别如下,虽然也区分了类似与selectOne,insert,delete等不同入参方法,但是最终都是调用的下面两个方法
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) // 查询操作
public int update(String statement, Object parameter) // 增删改操作
statement 接口全路径加方法名
parameter 输入参数
rowBounds 分页对象
2、在selectList方法中通过statement在configuration中获取MappedStatement对象,该对象包含sql以及出参入参等所有信息
MappedStatement ms = configuration.getMappedStatement(statement);
3、通过SqlSession中的执行器,调用执行器中的query方法
executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
4、query方法中,获取sql对象BoundSql以及session级别的缓存Key
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
5、调用抽象对象<基本执行器BaseExecutor> 的query方法,其中会通过Key进行获取是否存在缓存,如果不存在则进行查询
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
6、封装Statement对象(JDBC),获取**StatementHandler接口 对象,该对象封装了对JDBC的操作
ReuseExecutor.java
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
}
7、执行sql,并且通过ResultSetHandler对象封装返回值
PreparedStatementHandler.java
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleResultSets(ps);
}
看到这里应该太熟悉了吧,jdbc的方法
resultSetHandler.handleResultSets(ps) 对返回值的封装
六、拦截器插件
Executor在调用openSession()的时候会创建拦截器,在很多地方会创建,也在很多地方会执行,这里先举例一个执行的地方,就是在之前sql查询前,获取***StatementHandler***对象是进行执行。
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); //执行拦截器
return statementHandler;
}
private final List<Interceptor> interceptors = new ArrayList<>();
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
进入代码,最关键的是代码是Plugin.wrap(target, this);
public static Object wrap(Object target, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
这里用到了责任链模式,依次执行每一个拦截器
七、总结
关键对象的作用