一、准备工作
mybatis版本:3.5.2
public class Client {
@Test
public void selectUser() throws IOException {
//初始化参数,获取连接
String resource = "mybatis-config.xml";
InputStream inputStream = getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取接口反射对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = userDao.getUserById(1);
System.out.println(user);
sqlSession.close();
}
}
<?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>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<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://localhost:3306/school?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xc/dao/UserMapper.xml"/>
</mappers>
</configuration>
二、SqlSessionFactory初始化
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1)创建SqlSessionFactoryBuilder
建造者模式,SqlSessionFactoryBuilder 类中都是通过不同的入参重载方法返回SqlSessionFactory
public class SqlSessionFactoryBuilder {
//创建SqlSessionFactoryBuilder对象
public SqlSessionFactoryBuilder() {
}
//调用build一个入参的方法
public SqlSessionFactory build(InputStream inputStream) {
//再调用build三个入参的重载方法
return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
//创建XMLConfigBuilder对象
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//解析mybatis配置文件
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;
}
}
2)创建XMLConfigBuilder对象,根据配置文件输入流创建Document对象
public class XMLConfigBuilder extends BaseBuilder {
private boolean parsed;
//xml解析器
private final XPathParser parser;
private String environment;
private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
//重载方法之间的调用
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
//xml解析器根据配置文件流创建Document对象
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
//具体逻辑
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
//创建Configuration对象,注册乱七八糟的别名
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
}
3)解析mybatis配置文件,封装到Configuration对象中
public class XMLConfigBuilder extends BaseBuilder {
//默认设置为false
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
//只解析一次,Configuration配置文件是全局的,只能被解析一次
parsed = true;
//获取根节点configuration
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
//解析根节点configuration下的子节点
private void parseConfiguration(XNode root) {
try {
//解析properties元素
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
//解析environment元素
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
//解析mappers元素
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
}
解析properties元素
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
//将properties配置文件的name和value属性set到Properties对象
Properties defaults = context.getChildrenAsProperties();
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
//将配置文件资源信息放入Properties对象
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
//最后放入configuation对象中
configuration.setVariables(defaults);
}
}
解析environment(环境)元素
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
//解析environments节点的default属性的值
//例如: <environments default="dev">
environment = context.getStringAttribute("default");
}
//递归解析environments子节点
for (XNode child : context.getChildren()) {
/*
<environments default="dev">
<environment id="test">... </environment>
<environment id="dev">... </environment>
</environments>
*/
//通过default默认选择dev环境还是test环境,切换环境
String id = child.getStringAttribute("id");
//isSpecial就是根据由environments的default属性去选择对应的enviroment
if (isSpecifiedEnvironment(id)) {
//事务
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//数据源
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
//创建environment对象放入configuration对象里
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
解析mappers元素
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
//包扫描方式
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
//路径加载方法
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建mappersxml对象XMLMapperBuilder
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
//解析XMLMapperBuilder
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
解析XMLMapperBuilder
public void parse() {
// 判断是否已经加载过
if (!configuration.isResourceLoaded(resource)) {
// 解析 <mapper> 节点
configurationElement(parser.evalNode("/mapper"));
// 标记一下,已经加载过了
configuration.addLoadedResource(resource);
// 绑定映射器到namespace
bindMapperForNamespace();
}
// 处理 configurationElement 中解析失败的<resultMap>
parsePendingResultMaps();
// 处理configurationElement 中解析失败的<cache-ref>
parsePendingCacheRefs();
// 处理 configurationElement 中解析失败的 SQL 语句
parsePendingStatements();
}
解析 节点
private void configurationElement(XNode context) {
try {
// 获取namespace属性, 其代表者这个文档的标识
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
// 解析 <cache-ref> 节点
cacheRefElement(context.evalNode("cache-ref"));
// 解析 <cache> 节点
cacheElement(context.evalNode("cache"));
// 解析 </mapper/parameterMap> 节点
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
// 解析 </mapper/resultMap> 节点
resultMapElements(context.evalNodes("/mapper/resultMap"));
// 解析 </mapper/sql> 节点
sqlElement(context.evalNodes("/mapper/sql"));
// 解析 select|insert|update|delet 节点
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
}
}
解析 select | insert | update | delet 节点
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
//创建XMLStatementBuilder对象
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
//解析对象
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
将获取到的所有属性添加到addMappedStatement方法中,之后会生成MappedStatement对象
public void parseStatementNode() {
...
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String resultType = context.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
String resultMap = context.getStringAttribute("resultMap");
String resultSetType = context.getStringAttribute("resultSetType");
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
if (resultSetTypeEnum == null) {
resultSetTypeEnum = configuration.getDefaultResultSetType();
}
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
String resultSets = context.getStringAttribute("resultSets");
//将获取到的所有属性添加到此方法
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
将select|insert|update|delete标签属性放入MappedStatement 对象
bindMapperForNamespace(); 绑定映射器到namespace
knownMappers是一个map,key为接口Class对象,value为MapperProxyFaxtory工厂
MapperProxyFaxtory工厂,最终会通过此工厂创建UserDao的代理对象
4)将Configuration对象包装到DefaultSqlSessionFactory对象属性中
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
则SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
生成的SqlSessionFactory工厂的具体实现为DefaultSqlSessionFactory
- environment:环境对象,包含数据库连接信息
- defaultExecutorType:后续执行sql的执行器;SIMPLE普通增删改查,还有批量执行器,存储过程执行器
- mapperRegistry:namespace绑定的接口。key:接口Class对象,value:接口信息,后续生成代理对象
- interceptorChain:拦截器,后续在四大对象中使用
- typeHandlerRegistry:数据库和java的数据类型转换器
- typeAliasRegistry:mapper文件中的默认别名设置
- mappedStatements:key:具体方法名,value:MappedStatement对象,关于方法sql、参数等等所有信息
三、获取SqlSession对象
1)SqlSession sqlSession = sqlSessionFactory.openSession()
public class DefaultSqlSessionFactory implements SqlSessionFactory {
@Override
public SqlSession openSession() {
//设置执行性为默认的SIMPLE
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
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);
//生成SqlSession
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();
}
}
}
2)创建普通执行器
public class Configuration {
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);
}
//二级缓存全局开关,默认开启。具体使用还需要在mapperxml中添加 <cache />
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
//执行拦截器,重新包装执行器返回
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
}
使用CachingExecutor执行器好处,在每次查询前先查询缓存数据,使用装饰者模式,将查询方法包装在内。
3)根据configuration、executor等信息获取DefaultSqlSession**
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
四、getMapper获取接口的代理对象
1)UserDao userDao = sqlSession.getMapper(UserDao.class)
实现SqlSesion接口的getMapper方法
public class DefaultSqlSession implements SqlSession {
@Override
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
}
调用配置类getMapper方法
public class Configuration {
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
}
public class MapperRegistry {
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//根据sqlSessionFactory工厂初始化 knownMappers key:接口Class,value:接口信息MapperProxyFactory对象
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);
}
}
}
2)Proxy.newProxyInstance动态代理获取接口代理对象
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();
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) {
/**
* 1.指定当前目标对象使用的类加载器
* 2.目标对象实现的接口类型
* 3.事情处理,执行目标对象方法时,会触发事情处理器方法(会把当前执行的目标对象方法作为参数传入)
*/
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
mapperProxy的MapperProxy类实现了InvocationHandler接口,具体触发事件在invoke内,具体下面讲。
五、查询流程
1)User user = userDao.getUserById(1);进入动态代理invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//判断是否Object对象里toString,hashcode等方法,执行默认invoke
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (method.isDefault()) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//将method包装为MapperMethod方法
final MapperMethod mapperMethod = cachedMapperMethod(method);
//执行方法
return mapperMethod.execute(sqlSession, args);
}
MapperMethod 对象,包含sql类型,方法路径,返回值等信息
2)执行MapperMethod 类执行方法
public class MapperMethod {
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
//判断sql类型,增删改查
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);
//返回map
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
//返回一个
//封装参数,将参数放入map中,并指定key
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;
}
}
selectOne方法,调用selectList方法,返回多个报错
public class DefaultSqlSession implements SqlSession {
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
//selectList方法具体实现
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//根据方法名全类名字符串获取MappedStatemets对象,configuration对象初始化时生成
MappedStatement ms = configuration.getMappedStatement(statement);
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();
}
}
}
3)执行器sql方法
wrapCollection(parameter) 方法
设置参数map的默认值,集合key为list,数组key为array
private Object wrapCollection(final Object object) {
if (object instanceof Collection) {
StrictMap<Object> map = new StrictMap<>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap<Object> map = new StrictMap<>();
map.put("array", object);
return map;
}
return object;
}
缓存执行器
public class CachingExecutor implements Executor {
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//绑定sql
BoundSql boundSql = ms.getBoundSql(parameterObject);
//创建缓存key
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
//查询方法
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
}
绑定sql包含sql语句,每个占位符字段类型,具体的值value
创建缓存key = 方法名+sql语句+参数类型+参数值+额外参数
查询方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
//获取此mappserxml是否开启二级缓存
Cache cache = ms.getCache();
if (cache != null) {
//是否设置刷新
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
//根据key查缓存,如果查不到。查询数据库,并把结果放入二级缓存
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
//普通执行器的查询方法
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
缓存执行器方法执行后执行普通执行器的查询方法
public abstract class BaseExecutor implements Executor {
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
//根据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);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
//具体执行方法
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
//sql执行方法
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
//将查询结果放入本地缓存(一级缓存)
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
}
sql执行方法
public class SimpleExecutor extends BaseExecutor {
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//预编译sql
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
}
创建PreparedStatementHandler时候,其父类BaseStatementHandler会创建ParameterHandler(预编译sql)和ResultSetHandler(封装结果集)
public class RoutingStatementHandler implements StatementHandler {
private final StatementHandler delegate;
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
}
StatementHandler对象,拦截器,包装重新返回
public class Configuration {
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;
}
}
configuration.newStatementHandler创建StatementHandler(Statement处理器)
生成PreparedStatementHandler,预编译属性
预编译sql
public class SimpleExecutor extends BaseExecutor {
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
//获取连接
Connection connection = getConnection(statementLog);
//预编译
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
}
进入PreparedStatementHandler的prepare,调用基类的方法
public abstract class BaseStatementHandler implements StatementHandler {
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//实例化Statement
statement = instantiateStatement(connection);
//设置超时
setStatementTimeout(statement, transactionTimeout);
//设置读取条数
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
}
而instantiateStatement是基类留给子类去实现,所有调用PreparedStatementHandler的instantiateStatement
这里就是jdbc的代码,connection.prepareStatement创建PrepareStatement对象
public class PreparedStatementHandler extends BaseStatementHandler {
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
}
预编译就是将sql变成一个函数,函数的变量用占位符表示,后面注入的参数系统默认它仅仅是一个参数,而不会认为是一个sql语句,不会再次编译。
4)ParameterHandler
handler.parameterize(stmt);
public class DefaultParameterHandler implements ParameterHandler {
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
//循环设参数
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
//不同类型的set方法不同,委派给子类的setParameter方法
jdbcType = configuration.getJdbcTypeForNull();
}
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
}
5)TypeHandler接口
类型处理器接口,它在ParameterHandler和ResultSetHandler都用到,用于对类型的转换。
举个例子,比如String
public class StringTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName)
throws SQLException {
return rs.getString(columnName);
}
}
在ParamterHandler中,使用setParameter方法,它用于将传入的parameter设置成数据库的类型
在ResultSetHandler中,使用getResult方法,它用于将数据库类型转换为返回值的类型
6)ResultSetHandler
https://zoyi14.smartapps.cn/pages/note/index?slug=ec2894eff3ad&origin=userPage&_swebfr=1&_swebFromHost=baiduboxapp
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/148670.html