- 浏览: 14344 次
- 性别:
- 来自: 成都
最新评论
@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);
}
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);
}
BaseExecutor#createCacheKey
@Override public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {[size=x-small][/size] if (closed) { throw new ExecutorException("Executor was closed."); } CacheKey cacheKey = new CacheKey(); cacheKey.update(ms.getId()); cacheKey.update(rowBounds.getOffset()); cacheKey.update(rowBounds.getLimit()); cacheKey.update(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); // mimic DefaultParameterHandler logic for (ParameterMapping parameterMapping : parameterMappings) { if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { 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); } cacheKey.update(value); } } if (configuration.getEnvironment() != null) { // issue #176 cacheKey.update(configuration.getEnvironment().getId()); } return cacheKey; }
根据参数值,RowBounds,ParameterMapping确定缓存Key,每次update会更新Cachekey中的属性,equals的时候会比较各个字段的值,如果两次查询所传入的参数值,ParameterMapping都相等那么就是相同的cacheKey。
public void update(Object object) { int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object); count++; checksum += baseHashCode; baseHashCode *= count; hashcode = multiplier * hashcode + baseHashCode; updateList.add(object); } @Override public boolean equals(Object object) { if (this == object) { return true; } if (!(object instanceof CacheKey)) { return false; } final CacheKey cacheKey = (CacheKey) object; if (hashcode != cacheKey.hashcode) { return false; } if (checksum != cacheKey.checksum) { return false; } if (count != cacheKey.count) { return false; } for (int i = 0; i < updateList.size(); i++) { Object thisObject = updateList.get(i); Object thatObject = cacheKey.updateList.get(i); if (!ArrayUtil.equals(thisObject, thatObject)) { return false; } } return true; }
createCacheKey方法在Excutor接口定义由BaseExecutor实现,Executor接口的继承接口如下:
[img]
http://my.iteye.com/admin/picture/138355
[/img]
除CachingExecutor之外直接实现Excutor,其他接口均是继承自BaseExcutor,而CachingExecutor只是对其他Executor进行包装:
public class CachingExecutor implements Executor { private final Executor delegate; //二级事务缓存 private final TransactionalCacheManager tcm = new TransactionalCacheManager(); public CachingExecutor(Executor delegate) { this.delegate = delegate; delegate.setExecutorWrapper(this); }
@Override public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { //此处获取的是SynchronizedCache的实例,在装饰的对象缓存方法加上Synchronized,二级缓存 Cache cache = ms.getCache(); if (cache != null) { flushCacheIfRequired(ms); //只有对结果处理器为空的才使用二级缓存 //TODO为什么 if (ms.isUseCache() && resultHandler == null) { //parameterMapping只允许存在IN类型的参数映射 ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") //获取事务缓存(二级缓存//TODO) List<E> list = (List<E>) tcm.getObject(cache, key); //缓存为空则委托子类(SimpleExecutor查询),否则直接返回二级缓存结果 if (list == null) { //BaseExecutor#query list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
此处获取默认缓存是SynchronizedCache,原因是在XMLMapperBuilder#cacheElement解析<cache>节点构建缓存,调用BuilderAssistant#useNewCache,下面是构建缓存链的几个重要的流程:
public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass, Long flushInterval, Integer size, boolean readWrite, boolean blocking, Properties props) { //缓存id为当前xml命名空间 Cache cache = new CacheBuilder(currentNamespace) //没指定实现默认使用PerpetualCache,内部是HashMap .implementation(valueOrDefault(typeClass, PerpetualCache.class)) //没指定过期装饰器默认使用最近最少使用LRUCache对PerpetualCache进行装饰 .addDecorator(valueOrDefault(evictionClass, LruCache.class)) .clearInterval(flushInterval) .size(size) .readWrite(readWrite) .blocking(blocking) .properties(props) .build(); //添加到配置configuration configuration.addCache(cache); //设置当前缓存以便为MapperStatement使用 currentCache = cache; return cache; } public Cache build() { setDefaultImplementations(); //构造PerpetualCache Cache cache = newBaseCacheInstance(implementation, id); setCacheProperties(cache); // issue #352, do not apply decorators to custom caches if (PerpetualCache.class.equals(cache.getClass())) { //添加底层基础装饰器PerpetualCache为第一层,LruCache为第二层 for (Class<? extends Cache> decorator : decorators) { cache = newCacheDecoratorInstance(decorator, cache); //给LruCache设置相应属性,主要是size,默认1024 setCacheProperties(cache); } //设置装饰器链 cache = setStandardDecorators(cache); } else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) { cache = new LoggingCache(cache); } return cache; } //设置默认实现和默认最下层的装饰器 private void setDefaultImplementations() { if (implementation == null) { implementation = PerpetualCache.class; if (decorators.isEmpty()) { decorators.add(LruCache.class); } } } private Cache setStandardDecorators(Cache cache) { try { //再次检查是否设置上 MetaObject metaCache = SystemMetaObject.forObject(cache); if (size != null && metaCache.hasSetter("size")) { metaCache.setValue("size", size); } if (clearInterval != null) { //添加过期feature cache = new ScheduledCache(cache); ((ScheduledCache) cache).setClearInterval(clearInterval); } if (readWrite) { //开启readWrite只能将实现了Serializable的对象添加到缓存 cache = new SerializedCache(cache); } //日志记录缓存命中率 cache = new LoggingCache(cache); //给缓存中add put size方法加上 SynchronizedCache cache = new SynchronizedCache(cache); if (blocking) { //blocking=true,是否阻塞 //每一个key都对应一把锁,当get的时候请求锁,延迟时间后未获取到锁抛出异常 cache = new BlockingCache(cache); } return cache; } catch (Exception e) { throw new CacheException("Error building standard cache decorators. Cause: " + e, e); } }
private void flushCacheIfRequired(MappedStatement ms) { //二级缓存 Cache cache = ms.getCache(); //MapperBuilderAssistant#292 // .flushCacheRequired(valueOrDefault(flushCache, !isSelect)) //如果没有设置了flushCache ,则查询语句都是默认开启二级缓存,即不清除 if (cache != null && ms.isFlushCacheRequired()) { //flushCache=true或者是不是select //清除当前缓存 tcm.clear(cache); } }
单独解释下 tcm.clear(cache)
tcm是CachingExecutor的实例变量也是CachingExecutor被叫做CachingExecutor的原因,既然说到了缓存也说下CachingExecutor:
public class CachingExecutor implements Executor { private final Executor delegate; private final TransactionalCacheManager tcm = new TransactionalCacheManager(); public CachingExecutor(Executor delegate) { this.delegate = delegate; delegate.setExecutorWrapper(this); } @Override public Transaction getTransaction() { return delegate.getTransaction(); } @Override public void close(boolean forceRollback) { try { //issues #499, #524 and #573 if (forceRollback) { tcm.rollback(); } else { tcm.commit(); } } finally { delegate.close(forceRollback); } } @Override public boolean isClosed() { return delegate.isClosed(); } @Override public int update(MappedStatement ms, Object parameterObject) throws SQLException { flushCacheIfRequired(ms); return delegate.update(ms, parameterObject); } @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); } @Override public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException { flushCacheIfRequired(ms); return delegate.queryCursor(ms, parameter, rowBounds); } @Override public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { //二级缓存 Cache cache = ms.getCache(); if (cache != null) { flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") List<E> list = (List<E>) tcm.getObject(cache, key); if (list == null) { list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); } @Override public List<BatchResult> flushStatements() throws SQLException { return delegate.flushStatements(); } @Override public void commit(boolean required) throws SQLException { delegate.commit(required); tcm.commit(); } @Override public void rollback(boolean required) throws SQLException { try { delegate.rollback(required); } finally { if (required) { tcm.rollback(); } } } private void ensureNoOutParams(MappedStatement ms, BoundSql boundSql) { if (ms.getStatementType() == StatementType.CALLABLE) { for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) { if (parameterMapping.getMode() != ParameterMode.IN) { throw new ExecutorException("Caching stored procedures with OUT params is not supported. Please configure useCache=false in " + ms.getId() + " statement."); } } } } @Override public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) { return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql); } @Override public boolean isCached(MappedStatement ms, CacheKey key) { return delegate.isCached(ms, key); } @Override public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) { delegate.deferLoad(ms, resultObject, property, key, targetType); } @Override public void clearLocalCache() { delegate.clearLocalCache(); } //是否有必要清除缓存,select语句不进行清除,或者表明当前查询需要进行清除 private void flushCacheIfRequired(MappedStatement ms) { //这里获取的是二级缓存 Cache cache = ms.getCache(); if (cache != null && ms.isFlushCacheRequired()) { tcm.clear(cache); } } @Override public void setExecutorWrapper(Executor executor) { throw new UnsupportedOperationException("This method should not be called"); } } TransactionalCacheManager:缓存的事务管理器 TransactionalCacheManager被CachingExecutor持有,默认同一个SQLSession中,所有的 Cache(MapperStatement中的cache 二级缓存),都被这个缓存管理器管理public class TransactionalCacheManager { private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap<Cache, TransactionalCache>(); //清除某个mapper对应的cache或注解声明的cache对应的TransactionalCache public void clear(Cache cache) { getTransactionalCache(cache).clear(); } public Object getObject(Cache cache, CacheKey key) { return getTransactionalCache(cache).getObject(key); } public void putObject(Cache cache, CacheKey key, Object value) { getTransactionalCache(cache).putObject(key, value); } //提交当前事务缓存 public void commit() { for (TransactionalCache txCache : transactionalCaches.values()) { txCache.commit(); } } //回滚所有事务缓存 public void rollback() { for (TransactionalCache txCache : transactionalCaches.values()) { txCache.rollback(); } } private TransactionalCache getTransactionalCache(Cache cache) { TransactionalCache txCache = transactionalCaches.get(cache); if (txCache == null) { txCache = new TransactionalCache(cache); transactionalCaches.put(cache, txCache); } return txCache; } }
事务缓存--应该叫缓存事务:TransactionalCache
为底层Cache增加事务功能,简单来说即commit和rollback功能。
commit即将entriesToAddOnCommit提交到底层缓存中,
rollback即回退public class TransactionalCache implements Cache { private static final Log log = LogFactory.getLog(TransactionalCache.class); //包装类 private final Cache delegate; //是否在提交的时候清除底层缓存 private boolean clearOnCommit; //提交的时候要被添加到缓存中的对象 private final Map<Object, Object> entriesToAddOnCommit; //未命中的对象 private final Set<Object> entriesMissedInCache; public TransactionalCache(Cache delegate) { this.delegate = delegate; //默认false this.clearOnCommit = false; this.entriesToAddOnCommit = new HashMap<Object, Object>(); this.entriesMissedInCache = new HashSet<Object>(); } @Override public String getId() { return delegate.getId(); } @Override public int getSize() { return delegate.getSize(); } @Override public Object getObject(Object key) { // issue #116 //底层缓存获取为空添加到entriesMissedInCache中 Object object = delegate.getObject(key); if (object == null) { entriesMissedInCache.add(key); } // issue #146 //If a session is closed with no commit/rollback, 2nd level caches should be updated if the session just executed selects 如果clearOnCommit为true即执行过clear,clear在CachingExcutor中flushCacheIfRequired调用,在调用update方法时flushCacheIfRequired返回true if (clearOnCommit) { return null; } else { return object; } } @Override public ReadWriteLock getReadWriteLock() { return null; } //放入entriesToAddOnCommit等待提交 @Override public void putObject(Object key, Object object) { entriesToAddOnCommit.put(key, object); } @Override public Object removeObject(Object key) { return null; } //清除待提交,设置标志 @Override public void clear() { clearOnCommit = true; entriesToAddOnCommit.clear(); } //将当前队列待提交的数据提交到缓存中,并且重新设置标志,清空队列 public void commit() { if (clearOnCommit) { delegate.clear(); } flushPendingEntries(); reset(); } public void rollback() { unlockMissedEntries(); reset(); } private void reset() { clearOnCommit = false; entriesToAddOnCommit.clear(); entriesMissedInCache.clear(); } private void flushPendingEntries() { for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) { delegate.putObject(entry.getKey(), entry.getValue()); } //同时也将未命中的数据在缓存中设置为空 for (Object entry : entriesMissedInCache) { if (!entriesToAddOnCommit.containsKey(entry)) { delegate.putObject(entry, null); } } } //去掉缓存中未命中的数据 private void unlockMissedEntries() { for (Object entry : entriesMissedInCache) { try { delegate.removeObject(entry); } catch (Exception e) { log.warn("Unexpected exception while notifiying a rollback to the cache adapter." + "Consider upgrading your cache adapter to the latest version. Cause: " + e); } } } }
BaseExecutor#query@SuppressWarnings("unchecked") @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()); //使用同一个sqlSession关闭的时候会调用Executor.close if (closed) { throw new ExecutorException("Executor was closed."); } //与之前不同的是这里清除的是一级缓存 //queryStack的作用是当多个查询使用的是同一个SqlSession即同一个Executor时, //这些查询之间是并发进行的,如果后面的某个select语句的flushCache=true会导致其他语句的缓存被清除,即一个flushCache导致其他语句缓存失效,这是应该避免的,所以有且仅仅当当前flushCache=true的语句是当前session的第一个语句或者当前语句总是在当前session最先执行,即可保证其他缓存不被清除 if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { //每执行一次++1,可判断当前是否能进行缓存清除 queryStack++; //同二级缓存只有在resultHandler为空的情况下一级缓存才保持有效 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { //如果list不为空处理callable语句 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { //从数据库获取 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { //最后执行 queryStack--; } //查询完成后执行延迟加载,如果是语句中包含嵌套语句,并且嵌套语句的值已经在一级缓存中,就调用当前Executor的deferLoad生成一个,DeferredLoad包含当前返回结果的MetaObject,objectFactory,resultExtractor等。这里执行load方法就从缓存中获取嵌套的语句值设置给自己,达到加快速度的目的,queryStack=0代表着当前查询结束 if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); //如果本地缓存scope 是语句级清除当前缓存 if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; }
SimpleExecutor#doQuery
BaseExecutor执行query真正调用的是SimpleExecutor的doQuery方法@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); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
Configuration#newStatementHandler 创建StatementHandler
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { //RoutingStatementHandler是几种StatementHandler的封装 StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) //前面执行了Executor的拦截器,这里执行的是StatementHandler的拦截器,即此处的拦截器被当做StatementHandler interceptorChain.pluginAll(statementHandler); return statementHandler; }
SimpleExecutor#prepareStatement 创建预处理语句,设置参数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; }
BaseExecutor#getConnection
获取Connection对Connection进行动态代理,添加日志功能protected Connection getConnection(Log statementLog) throws SQLException { Connection connection = transaction.getConnection(); if (statementLog.isDebugEnabled()) { return ConnectionLogger.newInstance(connection, statementLog, queryStack); } else { return connection; } }
RoutingStatementHandler#prepare
调用被装饰的SatementHandler的prepare
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { return delegate.prepare(connection, transactionTimeout); }
BaseStatementHandler#preparepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); Statement statement = null; try { 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); } }
PreparedStatementHandler#instantiateStatement@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() != null) { return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } else { return connection.prepareStatement(sql); } }
//PreparedStatementHandler#parameterize @Override public void parameterize(Statement statement) throws SQLException { //BaseStatementHanlder构造方法 // this.parameterHandler = configuration.newParameterHandler(mappedStatement, //parameterObject, boundSql); parameterHandler.setParameters((PreparedStatement) statement); } //DefaultParameterHandler#setParameters /** 遍历parameterMappings,获取当前参数中的属性名称,如果boundsql有附加参数,第一优先级为附加参数,如果已经在Configuration中配置了自定义类型处理器,使用自定义类型处理器设置参数,否则使用MetaObject获取参数中的值,最后调用TypeHandler设置参数值,这里的BaseTypeHandler中setParameter调用子类的setNonNullParameter,至此SimpleExecutor的prepareStatement就执行完成了,SimpleExecutor的doQuery方法已经完成了StatementHandler的生成和Statement的生成,下一步就是执行带参数的Statement, statement被传入StatementHandler(RoutingStatementHandler)的query继续向下委托 **/ @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) { jdbcType = configuration.getJdbcTypeForNull(); } try { typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
PreparedStatementHandler#query
执行完语句,PreparedStatementHandler回调resultSetHandler的handleResultSets方法,resultSetHandler是在BaseHandler中的构造方法中进行初始化的
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.<E> handleResultSets(ps); }
发表评论
-
MyBatis原理(2)-执行流程 4 Mapper的执行
2018-09-07 11:15 763执行方式2: DeptMapper mapper ... -
MyBatis原理(2)-执行流程 3 处理结果集
2018-09-07 10:24 872DefaultResultSetHandler#handleR ... -
MyBatis原理(2)-执行流程 1 BoundSql生成
2018-08-31 17:09 1265MyBatis执行两种方式: 1. SqlSession ... -
MyBatis原理(1)-启动流程3- mapper 加载
2018-08-25 22:27 8611.接着上一篇文章解析mapper第一步 mapperEle ... -
MyBatis原理(1)-启动流程2
2018-08-24 17:21 5551.XMLConfigBuilder.parse ... -
MyBatis原理(1)-启动流程1
2018-08-23 17:10 1143概述:本文按三个部分依次循序渐进对mybatis源码-原理进行 ...
相关推荐
在这个场景中,“逆向工程mybatis-generator-1.3.2”指的是对MyBatis Generator 1.3.2版本的源代码或执行流程进行逆向分析。MyBatis Generator(MBG)是一个强大的工具,能够自动生成MyBatis接口和映射器XML文件,...
这里我们将深入探讨MBG的核心功能、工作原理以及如何使用mybatis-generator-core-1.3.2.jar这个版本来自动化生成代码。 首先,MyBatis Generator基于数据库表结构,通过配置文件指定数据库连接信息、表名以及需要...
总的来说,`mybatis-3-master` 源码分析可以帮助我们理解 MyBatis 内部的工作原理,提高我们对 SQL 执行流程、对象映射机制的理解,从而更好地优化数据库操作,提升系统性能。同时,通过阅读源码,开发者还能学习到...
在深入探讨MyBatis 3.3.0的源码之前,先了解一下这个框架的基本概念和工作原理。 MyBatis的核心是SqlSession,它是与数据库交互的接口,通过SqlSessionFactory创建。SqlSessionFactory是配置信息的工厂,它会根据...
Mybatis Generator的工作原理基于XML配置文件,开发者需要在配置文件中指定数据库连接信息、表名以及需要生成的代码类型。通过运行一个简单的Java类,该工具会读取配置文件,自动扫描指定的数据库表,然后根据配置...
在本压缩包“mybatis-3-mybatis-3.5.4-src-read.zip”中,包含了作者对MyBatis 3.5.4版本源码的阅读理解,特别进行了关键部分的注解和流程解析,对于学习和深入理解MyBatis的工作原理非常有帮助。 1. **MyBatis架构...
2. **工作原理** - 数据库连接:MyBatis-Auto-Generator-Core首先需要建立到数据库的连接,通过JDBC获取数据库元数据,包括表名、列名、数据类型等信息。 - 模板引擎:然后,它使用模板引擎(如FreeMarker或...
#### 二、MyBatis的工作原理 MyBatis的核心设计理念在于给予开发者足够的自由度来编写SQL语句,这使得SQL优化变得更为简单易行。与其他一些ORM框架不同,MyBatis不会自动生成SQL语句,而是需要开发者自行编写。这种...
MyBatis Generator 的工作原理是通过读取数据库元数据,根据预设的模板生成对应的 Java 源代码。它支持多种数据库,包括 MySQL、Oracle、SQL Server 等。在使用 MBG 时,我们需要创建一个 XML 配置文件,其中定义了...
2. **Executor**:执行器负责执行SQL,它是MyBatis的执行核心。它有多种实现,如SimpleExecutor、ReusedExecutor和BatchExecutor,分别对应不同的执行策略。 3. **StatementHandler**:处理SQL语句,包括预编译、...
通过分析和研究mybatis-3.2.2的源码,开发者可以深入了解MyBatis的工作流程,优化自己的代码,甚至为MyBatis贡献新的功能。对于Java开发者来说,深入理解MyBatis源码是提升自身技能和解决问题的重要途径。
通过对MyBatis 3.1.0源码的学习,开发者可以深入理解其内部工作流程,如Mapper接口的动态代理实现、XML解析与SQL构建、动态SQL的编译执行等,从而更好地利用MyBatis进行数据库操作,同时也能为自定义扩展和性能优化...
在本压缩包 "mybatis-3-mybatis-3.3.0.tar.gz" 中,包含了 MyBatis 的 3.3.0 版本的源码,这对于学习、理解和调试 MyBatis 的工作原理非常有帮助。 MyBatis 的核心设计理念是将 SQL 语句与 Java 代码分离,通过 XML...
总之,"跑通的Mybatis后端源码-WhenToMint"项目提供了一个实际运行的Mybatis应用示例,通过学习和分析这个项目,你可以深入理解Mybatis的工作原理,以及如何在实际项目中使用Mybatis进行数据库操作。同时,良好的...
通过上述分析,我们可以清晰地了解到Mybatis中SQL解析的整体流程:从创建SqlSessionFactory开始,到打开SqlSession,再到获取Mapper代理对象,最后执行SQL语句并获取结果。这一过程不仅展示了Mybatis强大的SQL解析...
MyBatis 是一款著名的Java持久层框架,它简化了数据库操作与Java对象之间的映射,提供了灵活的SQL构建和执行机制。在MyBatis-3.2.3这个版本中,我们可以深入研究其源码,了解其内部工作原理,这对于Java开发者尤其是...
MyBatis 3.2.6 版本是该框架的一个历史版本,对于学习MyBatis的源码、理解其工作原理以及对比不同版本间的差异具有重要意义。 在MyBatis 3.2.6中,我们可以关注以下几个核心知识点: 1. SQL映射:MyBatis的核心...
12. **MyBatis 执行流程**:了解 MyBatis 如何解析 XML 或注解,生成 PreparedStatement,执行 SQL,处理结果集,以及事务提交或回滚的过程。 13. **实战项目**:通过一个完整的案例,实践 MyBatis 的集成,包括...
MyBatis Generator的主要工作原理是通过读取数据库元数据,然后根据预设的模板生成相应的Java源代码和XML配置文件。这样,开发者就可以避免手动编写重复性的代码,从而节省大量时间,提高开发效率。 **主要组件和...
通过深入研究"Mybatis-3"的源码,我们可以理解其内部的执行流程,例如Executor的执行策略、StatementHandler的预编译和执行过程、ParameterHandler参数绑定的逻辑,以及ResultSetHandler结果集处理的细节。...