八SqlSession 执行 Mapper 过程详解
Posted archerLuo罗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了八SqlSession 执行 Mapper 过程详解相关的知识,希望对你有一定的参考价值。
- 源码地址:https://github.com/RononoaZoro/mybatis-book/tree/master 的 mybatis-book ( mybatis-chapter06 )
- 文章内容出自《Mybatis 3 源码深度解析》第六章
- 自己实现代码地址:https://github.com/RononoaZoro/mybatis-book/tree/master 的 archer-mybatis
package com.blog4java.mybatis.example;
import com.alibaba.fastjson.JSON;
import com.blog4java.common.DbUtils;
import com.blog4java.mybatis.example.entity.UserEntity;
import com.blog4java.mybatis.example.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.session.SqlSessionManager;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.List;
public class MybatisExample {
@Before
public void initData() {
DbUtils.initData();
}
@Test
public void testMybatis () throws IOException {
// 获取配置文件输入流
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 通过SqlSessionFactoryBuilder的build()方法创建SqlSessionFactory实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 调用openSession()方法创建SqlSession实例
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取UserMapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 执行Mapper方法,获取执行结果
List<UserEntity> userList = userMapper.listAllUser();
/*
// 兼容Ibatis,通过Mapper Id执行SQL操作
List<UserEntity> userList = sqlSession.selectList(
"com.blog4java.mybatis.com.blog4java.mybatis.example.mapper.UserMapper.listAllUser");
*/
System.out.println(JSON.toJSONString(userList));
}
}
1、核心配置类 Configuration 初始化
2、创建 SqlSession 对象
3、获取 UserMapper 的动态代理对象
// 获取UserMapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SqlSession.java 部分代码
public class SqlSession {
/**
* Retrieves a mapper.
* @param <T> the mapper type
* @param type Mapper interface class
* @return a mapper bound to this SqlSession
*/
<T> T getMapper(Class<T> type);
}
DefaultSqlSession.java 部分代码
/**
*
* The default implementation for {@link SqlSession}.
* Note that this class is not Thread-Safe.
*
* @author Clinton Begin
*/
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
public DefaultSqlSession(Configuration configuration, Executor executor) {
this(configuration, executor, false);
}
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
}
Configuration.java 部分代码
public class Configuration {
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
public void addMappers(String packageName, Class<?> superType) {
mapperRegistry.addMappers(packageName, superType);
}
public void addMappers(String packageName) {
mapperRegistry.addMappers(packageName);
}
public <T> void addMapper(Class<T> type) {
mapperRegistry.addMapper(type);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
}
MapperRegistry.java 部分代码
- Configuration 初始化会填充 MapperRegistry 对象
public class MapperRegistry {
// Configuration对象引用
private final Configuration config;
// 用于注册Mapper接口Class对象,和MapperProxyFactory对象对应关系
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
public MapperRegistry(Configuration config) {
this.config = config;
}
// 根据Mapper接口Class对象获取Mapper动态代理对象
@SuppressWarnings("unchecked")
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);
}
}
// 根据Mapper接口Class对象,创建MapperProxyFactory对象,并注册到knownMappers属性中
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
}
MapperProxyFactory.java 部分代码
-
默认使用 jdk 的 Proxy 生成 Mapper 的代理类
-
Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy)
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
4、执行 Mapper 的增删查改方法
// 执行Mapper方法,获取执行结果
List<UserEntity> userList = userMapper.listAllUser();
4.1、执行代理类的 invoke 方法
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 从Object类继承的方法不做处理
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
// jdk8 接口默认方法
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
// 对Mapper接口中定义的方法进行封装,生成MapperMethod对象
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}
MapperMethod.java 部分代码
public class MapperMethod {
private final SqlCommand command;
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
// 其中command为MapperMethod构造是创建的SqlCommand对象
// 获取SQL语句类型
switch (command.getType()) {
case INSERT: {
// 获取参数信息
Object param = method.convertArgsToSqlCommandParam(args);
// 调用SqlSession的insert()方法,然后调用rowCountResult()方法统计行数
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
// 调用SqlSession对象的update()方法
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 = OptionalUtil.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;
}
}
4.2、执行 SQL
MapperMethod.java 部分代码
public class MapperMethod {
private Object rowCountResult(int rowCount) {
final Object result;
if (method.returnsVoid()) {
result = null;
} else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
result = rowCount;
} else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
result = (long) rowCount;
} else if (Boolean.class.equals(method.Springboot+Mybatis