赞
踩
SqlSession接口提供了查询,插入,更新,删除方法,Mybatis中所有的数据库交互都由SqlSession来完成。SqlSession 对象完全包含以数据库为背景的所有执行 SQL 操作的方法,它的底层封装了 JDBC 连接,可以用 SqlSession 实例来直接执行已映射的 SQL 语句。每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不能被共享,也是线程不安全的,使用完成后需要及时关闭
SqlSession 的创建需要借助于 SqlSessionFactory,SqlSessionFactory 是 Mybatis 的关键对象,每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心。创建代码示例如下:
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSessionFactory创建SqlSession的列表如下:
public interface SqlSessionFactory { SqlSession openSession(); SqlSession openSession(boolean autoCommit); SqlSession openSession(Connection connection); SqlSession openSession(TransactionIsolationLevel level); SqlSession openSession(ExecutorType execType); SqlSession openSession(ExecutorType execType, boolean autoCommit); SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level); SqlSession openSession(ExecutorType execType, Connection connection); Configuration getConfiguration(); }
直接分析默认使用的openSession()无参的方法,在DefaultSqlSessionFactory#openSession中,可以看到其调用的是openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)
这个方法:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { //1. 从配置中获取对应的环境 final Environment environment = configuration.getEnvironment(); // 获取事务工厂 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); //2. 根据数据源,事物隔离级别,是否自动提交创建事物管理器 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); //3. 创建Executor执行器 final Executor executor = configuration.newExecutor(tx, execType); //4. 返回DefaultSqlSession 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(); } }
该方法首先是根据事物工厂以及数据源工厂构造了一个事物管理器,之后创建一个Executor对象存入到DefaultSqlSession,后续DefaultSqlSession执行的时候便是通过Executor对象实例执行的。
Executor 接口定义了数据库操作的基本方法,其中 query*() 方法、update() 方法、flushStatement() 方法是执行 SQL 语句的基础方法,commit() 方法、rollback() 方法以及 getTransaction() 方法与事务的提交/回滚相关。Executor的是根据传入的executorType来创建的,有多个 Executor 接口的实现类,如下图所示:
创建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; }
在获取到SqlSession后,根据SqlSession获取对应Mapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
SqlSession创建的Mapper是从Configuration中的mapperRegistry获取的:
// Configuration#getMapper public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); } // MapperRegistry#getMapper public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
MapperProxyFactory 的核心功能就是创建 Mapper 接口的代理对象,在 MapperRegistry 中会依赖 MapperProxyFactory 的 newInstance() 方法创建代理对象,底层则是通过 JDK 动态代理的方式生成代理对象的
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);
}
由上面的流程可知,通过SqlSession获取到的mapper对象是一个代理对象,其执行逻辑在InvocationHandler的invoke方法中
通过分析 MapperProxyFactory 这个工厂类,我们可以清晰地看到MapperProxy 是生成 Mapper 接口代理对象的关键,它实现了 InvocationHandler 接口,接下来分析一下它的invoke方法
public class MapperProxy<T> implements InvocationHandler, Serializable { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // 如果是Object的方法,直接调用 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else { return cachedInvoker(method).invoke(proxy, method, args, sqlSession); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } private MapperMethodInvoker cachedInvoker(Method method) throws Throwable { try { // 尝试从methodCache缓存中查询方法对应的MapperMethodInvoker MapperMethodInvoker invoker = methodCache.get(method); if (invoker != null) { return invoker; } // 如果方法在缓存中没有对应的MapperMethodInvoker,则进行创建 return methodCache.computeIfAbsent(method, m -> { if (m.isDefault()) {//针对默认方法 try { // 这里根据JDK版本的不同,获取方法对应的MethodHandle的方式也有所不同 // 在JDK 8中使用的是lookupConstructor字段,而在JDK 9中使用的是 // privateLookupInMethod字段。获取到MethodHandle之后,会使用 // DefaultMethodInvoker进行封装 if (privateLookupInMethod == null) { return new DefaultMethodInvoker(getMethodHandleJava8(method)); } else { return new DefaultMethodInvoker(getMethodHandleJava9(method)); } } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) { throw new RuntimeException(e); } } else { // 对于其他方法,会创建MapperMethod并使用PlainMethodInvoker封装 return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())); } }); } catch (RuntimeException re) { Throwable cause = re.getCause(); throw cause == null ? re : cause; } } }
通过对 MapperProxy的invoke分析我们知道,MapperMethod 是最终执行 SQL 语句的地方,同时也记录了 Mapper 接口中的对应方法,其核心字段也围绕这两方面的内容展开
MapperMethod 的第一个核心字段是 command(SqlCommand 类型),其中维护了关联 SQL 语句的相关信息。在 MapperMethod$SqlCommand 这个内部类中,通过 name 字段记录了关联 SQL 语句的唯一标识,通过 type 字段(SqlCommandType 类型)维护了 SQL 语句的操作类型,这里 SQL 语句的操作类型分为 INSERT、UPDATE、DELETE、SELECT 和 FLUSH 五种。
public static class SqlCommand { //记录了关联 SQL 语句的唯一标识 private final String name; //维护了 SQL 语句的操作类型 private final SqlCommandType type; public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) { 获取Mapper接口中对应的方法名称 final String methodName = method.getName(); // 获取Mapper接口的类型 final Class<?> declaringClass = method.getDeclaringClass(); // 将Mapper接口名称和方法名称拼接起来作为SQL语句唯一标识, // 到Configuration这个全局配置对象中查找SQL语句 // MappedStatement对象就是Mapper.xml配置文件中一条SQL语句解析之后得到的对象 MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration); if (ms == null) { // 针对@Flush注解的处理 if (method.getAnnotation(Flush.class) != null) { name = null; type = SqlCommandType.FLUSH; } else { throw new BindingException("Invalid bound statement (not found): " + mapperInterface.getName() + "." + methodName); } } else { // 记录SQL语句唯一标识 name = ms.getId(); // 记录SQL语句的操作类型 type = ms.getSqlCommandType(); if (type == SqlCommandType.UNKNOWN) { throw new BindingException("Unknown execution method for: " + name); } } } public String getName() { return name; } public SqlCommandType getType() { return type; } private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName, Class<?> declaringClass, Configuration configuration) { //将Mapper接口名称和方法名称拼接起来作为SQL语句唯一标识 String statementId = mapperInterface.getName() + "." + methodName; if (configuration.hasStatement(statementId)) { return configuration.getMappedStatement(statementId); // 如果方法就定义在当前接口中,则证明没有对应的SQL语句,返回null } else if (mapperInterface.equals(declaringClass)) { return null; } // 如果当前检查的Mapper接口(mapperInterface)中不是定义该方法的接口(declaringClass), // 则会从mapperInterface开始,沿着继承关系向上查找递归每个接口, // 查找该方法对应的MappedStatement对象 for (Class<?> superInterface : mapperInterface.getInterfaces()) { if (declaringClass.isAssignableFrom(superInterface)) { MappedStatement ms = resolveMappedStatement(superInterface, methodName, declaringClass, configuration); if (ms != null) { return ms; } } } return null; } }
MapperMethod 的第二个核心字段是 method 字段(MethodSignature 类型),其中维护了 Mapper 接口中方法的相关信息。
public static class MethodSignature { //表示方法返回值是否为 Collection 集合或数组、Map 集合、void、Cursor、Optional 类型 private final boolean returnsMany; private final boolean returnsMap; private final boolean returnsVoid; private final boolean returnsCursor; private final boolean returnsOptional; //方法返回值的具体类型 private final Class<?> returnType; //如果方法的返回值为 Map 集合,则通过 mapKey 字段记录了作为 key 的列名。mapKey 字段的值是通过解析方法上的 @MapKey 注解得到的。 private final String mapKey; //记录了 Mapper 接口方法的参数列表中 ResultHandler 类型参数的位置。 private final Integer resultHandlerIndex; //记录了 Mapper 接口方法的参数列表中 RowBounds 类型参数的位置。 private final Integer rowBoundsIndex; //用来解析方法参数列表的工具类 private final ParamNameResolver paramNameResolver; public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) { Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface); if (resolvedReturnType instanceof Class<?>) { this.returnType = (Class<?>) resolvedReturnType; } else if (resolvedReturnType instanceof ParameterizedType) { this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType(); } else { this.returnType = method.getReturnType(); } // 根据返回值类型,初始化returnsVoid、returnsMany、returnsCursor、 // returnsMap、returnsOptional这五个与方法返回值类型相关的字段 this.returnsVoid = void.class.equals(this.returnType); this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray(); this.returnsCursor = Cursor.class.equals(this.returnType); this.returnsOptional = Optional.class.equals(this.returnType); // 如果返回值为Map类型,则从方法的@MapKey注解中获取Map中为key的字段名称 this.mapKey = getMapKey(method); this.returnsMap = this.mapKey != null; // 解析方法中RowBounds类型参数以及ResultHandler类型参数的下标索引位置, // 初始化rowBoundsIndex和resultHandlerIndex字段 this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class); this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class); // 创建ParamNameResolver工具对象,在创建ParamNameResolver对象的时候, // 会解析方法的参数列表信息 this.paramNameResolver = new ParamNameResolver(configuration, method); } }
MapperMethod实例拥有了SqlCommand,MethodSignature对象之后,就可以开始执行Sql的逻辑了;根据SqlCommand不同的执行类型以及MethodSignature返回值类型调用SqlSession执行Sql语句获取到执行结果
public Object execute(SqlSession sqlSession, Object[] args) { Object result; switch (command.getType()) { case INSERT: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); break; } case UPDATE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); break; } case DELETE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); break; } case SELECT: if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { result = executeForMany(sqlSession, args); } else if (method.returnsMap()) { result = executeForMap(sqlSession, args); } else if (method.returnsCursor()) { result = executeForCursor(sqlSession, args); } else { Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { result = Optional.ofNullable(result); } } break; case FLUSH: result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + command.getName()); } if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; }
在MapperMethod中调用SqlSession的查询方法selectList,在SqlSession中最终是通过Executor执行sql逻辑,代码如下:
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
//executor执行
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。