spring事务(spring/hibernate/dbcp)-源码分析

289 阅读5分钟

入口

dubbo接口,调用service类的事务业务方法。

spring事务拦截器-开始

。。。


最后一步
MethodProxy

public Object invoke(Object obj, Object[] args) throws Throwable {
  try {
    this.init();
    MethodProxy.FastClassInfo fci = this.fastClassInfo;
    return fci.f1.invoke(fci.i1, obj, args); //调用业务方法
  } catch (InvocationTargetException var4) {
    throw var4.getTargetException();
  } catch (IllegalArgumentException var5) {
    if (this.fastClassInfo.i1 < 0) {
      throw new IllegalArgumentException("Protected method: " + this.sig1);
    } else {
      throw var5;
    }
  }
}

service类的业务方法

包含多个sql

业务方法里的每个sql都会被拦截器拦截

CglibAopProxy

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
 Object oldProxy = null;
 boolean setProxyContext = false;
 Class<?> targetClass = null;
 Object target = null;
 try {
  if (this.advised.exposeProxy) {
   // Make invocation available if necessary.
   oldProxy = AopContext.setCurrentProxy(proxy);
   setProxyContext = true;
  }
  // May be null Get as late as possible to minimize the time we
  // "own" the target, in case it comes from a pool.
  target = getTarget();
  if (target != null) {
   targetClass = target.getClass();
  }
  List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  Object retVal;
  // Check whether we only have one InvokerInterceptor: that is,
  // no real advice, but just reflective invocation of the target.
  if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
   // We can skip creating a MethodInvocation: just invoke the target directly.
   // Note that the final invoker must be an InvokerInterceptor, so we know
   // it does nothing but a reflective operation on the target, and no hot
   // swapping or fancy proxying.
   retVal = methodProxy.invoke(target, args);
  }
  else {
   // We need to create a method invocation...
   retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); //
  }
  retVal = processReturnType(proxy, target, method, retVal);
  return retVal;
 }
 finally {
  if (target != null) {
   releaseTarget(target);
  }
  if (setProxyContext) {
   // Restore old proxy.
   AopContext.setCurrentProxy(oldProxy);
  }
 }
}

最后一步,和service一样,然后就进入dao的方法。

dao的方法

业务dao的方法


公司封装的hibernate基础公共dao

protected Object getUniqueResult(final QueryHelper helper) {
  String ObjectName = null == this.getModelClass() ? "" : this.getModelClass().getName() + ".";
  String methodName = "getUniqueResult";
  Transaction t = Cat.newTransaction("SQL", ObjectName + methodName);
  String queryStr = "NULL";
  if (helper != null && helper.getHql() != null) {
    queryStr = helper.getHql().toString();
  }

  Event methodEvent = this.logEvent("SQL.Method", "SELECT");
  String Database = this.getDBConnectionUrl();
  Event DBEvent = this.logEvent("SQL.Database", Database);
  Event typeEvent = this.logEvent("SQL.Type", "hibernate");
  t.addChild(methodEvent);
  t.addChild(DBEvent);
  t.addChild(typeEvent);
  t.addData(queryStr);

  Object var11;
  try {
    Object object = this.getHibernateTemplate().execute(new HibernateCallback() { //查询
      public Object doInHibernate(Session session) throws HibernateException, SQLException {
        return helper.getUniqueResult(session); //回调
      }
    });
    t.setStatus("0");
    var11 = object;
  } catch (Exception var15) {
    Cat.logError(var15);
    t.setStatus(var15.getClass().getSimpleName());
    throw var15;
  } finally {
    t.complete();
  }

  return var11;
}

hibernate查询

HibernateTemplate

/**
 * Execute the action specified by the given action object within a Session.
 * @param action callback object that specifies the Hibernate action
 * @param enforceNewSession whether to enforce a new Session for this template
 * even if there is a pre-bound transactional Session
 * @param enforceNativeSession whether to enforce exposure of the native
 * Hibernate Session to callback code
 * @return a result object returned by the action, or {@code null}
 * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
 */
protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNewSession, boolean enforceNativeSession)
  throws DataAccessException {

 Assert.notNull(action, "Callback object must not be null");

 Session session = (enforceNewSession ?
   SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
 boolean existingTransaction = (!enforceNewSession &&
   (!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
 if (existingTransaction) {
  logger.debug("Found thread-bound Session for HibernateTemplate");
 }

 FlushMode previousFlushMode = null;
 try {
  previousFlushMode = applyFlushMode(session, existingTransaction);
  enableFilters(session);
  Session sessionToExpose =
    (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session)); //创建会话对象
  T result = action.doInHibernate(sessionToExpose); //回调
  flushIfNecessary(session, existingTransaction);
  return result;
 }
 catch (HibernateException ex) {
  throw convertHibernateAccessException(ex);
 }
 catch (SQLException ex) {
  throw convertJdbcAccessException(ex);
 }
 catch (RuntimeException ex) {
  // Callback code threw application exception...
  throw ex;
 }
 finally {
  if (existingTransaction) {
   logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
   disableFilters(session);
   if (previousFlushMode != null) {
    session.setFlushMode(previousFlushMode);
   }
  }
  else {
   // Never use deferred close for an explicitly new Session.
   if (isAlwaysUseNewSession()) {
    SessionFactoryUtils.closeSession(session);
   }
   else {
    SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
   }
  }
 }
}

回调

HqlHelper

public Object getUniqueResult(Session session) {
 return this.getQuery(session).uniqueResult(); //查询
}

HibernateTemplate

/**
 * Invocation handler that suppresses close calls on Hibernate Sessions.
 * Also prepares returned Query and Criteria objects.
 * @see org.hibernate.Session#close
 */
private class CloseSuppressingInvocationHandler implements InvocationHandler {

 private final Session target;

 public CloseSuppressingInvocationHandler(Session target) {
  this.target = target;
 }

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  // Invocation on Session interface coming in...

  if (method.getName().equals("equals")) {
   // Only consider equal when proxies are identical.
   return (proxy == args[0]);
  }
  else if (method.getName().equals("hashCode")) {
   // Use hashCode of Session proxy.
   return System.identityHashCode(proxy);
  }
  else if (method.getName().equals("close")) {
   // Handle close method: suppress, not valid.
   return null;
  }

  // Invoke method on target Session.
  try {
   Object retVal = method.invoke(this.target, args); //

   // If return value is a Query or Criteria, apply transaction timeout.
   // Applies to createQuery, getNamedQuery, createCriteria.
   if (retVal instanceof Query) {
    prepareQuery(((Query) retVal)); //
   }
   if (retVal instanceof Criteria) {
    prepareCriteria(((Criteria) retVal));
   }

   return retVal;
  }
  catch (InvocationTargetException ex) {
   throw ex.getTargetException();
  }
 }
}
/**
 * Prepare the given Query object, applying cache settings and/or
 * a transaction timeout.
 * @param queryObject the Query object to prepare
 * @see #setCacheQueries
 * @see #setQueryCacheRegion
 * @see SessionFactoryUtils#applyTransactionTimeout
 */
protected void prepareQuery(Query queryObject) {
 if (isCacheQueries()) { //false,不是从缓存查询
  queryObject.setCacheable(true);
  if (getQueryCacheRegion() != null) {
   queryObject.setCacheRegion(getQueryCacheRegion());
  }
 }
 if (getFetchSize() > 0) {
  queryObject.setFetchSize(getFetchSize());
 }
 if (getMaxResults() > 0) {
  queryObject.setMaxResults(getMaxResults());
 }
 SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
}

AbstractQueryImpl

public Object uniqueResult() throws HibernateException {
  return uniqueElement(this.list()); //从查询集合里取第一个数据
}

QueryImpl

public List list() throws HibernateException {
  this.verifyParameters();
  Map namedParams = this.getNamedParams();
  this.before();

  List var2;
  try {
    var2 = this.getSession().list(this.expandParameterLists(namedParams), this.getQueryParameters(namedParams)); //查询
  } finally {
    this.after();
  }

  return var2;
}
public List list(String query, QueryParameters queryParameters) throws HibernateException {
  this.errorIfClosed();
  this.checkTransactionSynchStatus();
  queryParameters.validateParameters();
  HQLQueryPlan plan = this.getHQLQueryPlan(query, false);
  this.autoFlushIfRequired(plan.getQuerySpaces());
  List results = CollectionHelper.EMPTY_LIST;
  boolean success = false;
  ++this.dontFlushFromFind;

  try {
    results = plan.performList(queryParameters, this); //查询
    success = true;
  } finally {
    --this.dontFlushFromFind;
    this.afterOperation(success);
  }

  return results;
}

HQLQueryPlan

public List performList(QueryParameters queryParameters, SessionImplementor session) throws HibernateException {
  if (log.isTraceEnabled()) {
    log.trace("find: " + this.getSourceQuery());
    queryParameters.traceParameters(session.getFactory());
  }

  boolean hasLimit = queryParameters.getRowSelection() != null && queryParameters.getRowSelection().definesLimits();
  boolean needsLimit = hasLimit && this.translators.length > 1;
  QueryParameters queryParametersToUse;
  if (needsLimit) {
    log.warn("firstResult/maxResults specified on polymorphic query; applying in memory!");
    RowSelection selection = new RowSelection();
    selection.setFetchSize(queryParameters.getRowSelection().getFetchSize());
    selection.setTimeout(queryParameters.getRowSelection().getTimeout());
    queryParametersToUse = queryParameters.createCopyUsing(selection);
  } else {
    queryParametersToUse = queryParameters;
  }

  List combinedResults = new ArrayList();
  IdentitySet distinction = new IdentitySet();
  int includedCount = -1;

  for(int i = 0; i < this.translators.length; ++i) {
    List tmp = this.translators[i].list(session, queryParametersToUse); //查询
    if (needsLimit) {
      int first = queryParameters.getRowSelection().getFirstRow() == null ? 0 : queryParameters.getRowSelection().getFirstRow();
      int max = queryParameters.getRowSelection().getMaxRows() == null ? -1 : queryParameters.getRowSelection().getMaxRows();
      int size = tmp.size();

      for(int x = 0; x < size; ++x) {
        Object result = tmp.get(x);
        if (distinction.add(result)) {
          ++includedCount;
          if (includedCount >= first) {
            combinedResults.add(result);
            if (max >= 0 && includedCount > max) {
              return combinedResults;
            }
          }
        }
      }
    } else {
      combinedResults.addAll(tmp);
    }
  }

  return combinedResults;
}

QueryTranslatorImpl

public List list(SessionImplementor session, QueryParameters queryParameters) throws HibernateException {
  this.errorIfDML();
  QueryNode query = (QueryNode)this.sqlAst;
  boolean hasLimit = queryParameters.getRowSelection() != null && queryParameters.getRowSelection().definesLimits();
  boolean needsDistincting = (query.getSelectClause().isDistinct() || hasLimit) && this.containsCollectionFetches();
  QueryParameters queryParametersToUse;
  if (hasLimit && this.containsCollectionFetches()) {
    log.warn("firstResult/maxResults specified with collection fetch; applying in memory!");
    RowSelection selection = new RowSelection();
    selection.setFetchSize(queryParameters.getRowSelection().getFetchSize());
    selection.setTimeout(queryParameters.getRowSelection().getTimeout());
    queryParametersToUse = queryParameters.createCopyUsing(selection);
  } else {
    queryParametersToUse = queryParameters;
  }

  List results = this.queryLoader.list(session, queryParametersToUse); //查询
  if (needsDistincting) {
    int includedCount = -1;
    int first = hasLimit && queryParameters.getRowSelection().getFirstRow() != null ? queryParameters.getRowSelection().getFirstRow() : 0;
    int max = hasLimit && queryParameters.getRowSelection().getMaxRows() != null ? queryParameters.getRowSelection().getMaxRows() : -1;
    int size = ((List)results).size();
    List tmp = new ArrayList();
    IdentitySet distinction = new IdentitySet();

    for(int i = 0; i < size; ++i) {
      Object result = ((List)results).get(i);
      if (distinction.add(result)) {
        ++includedCount;
        if (includedCount >= first) {
          tmp.add(result);
          if (max >= 0 && includedCount - first >= max - 1) {
            break;
          }
        }
      }
    }

    results = tmp;
  }

  return (List)results;
}

Loader

protected List doList(SessionImplementor session, QueryParameters queryParameters) throws HibernateException {
  boolean stats = this.getFactory().getStatistics().isStatisticsEnabled();
  long startTime = 0L;
  if (stats) {
    startTime = System.currentTimeMillis();
  }

  List result;
  try {
    result = this.doQueryAndInitializeNonLazyCollections(session, queryParameters, true); //查询
  } catch (SQLException var8) {
    throw JDBCExceptionHelper.convert(this.factory.getSQLExceptionConverter(), var8, "could not execute query", this.getSQLString());
  }

  if (stats) {
    this.getFactory().getStatisticsImplementor().queryExecuted(this.getQueryIdentifier(), result.size(), System.currentTimeMillis() - startTime);
  }

  return result;
}

AbstractBatcher

public ResultSet getResultSet(PreparedStatement ps) throws SQLException {
  ResultSet rs = ps.executeQuery(); //查询
  this.resultSetsToClose.add(rs);
  this.logOpenResults();
  return rs;
}

dbcp

hibernate委托给了dbcp

DelegatingPreparedStatement

public ResultSet executeQuery() throws SQLException {
  this.checkOpen();

  try {
    return DelegatingResultSet.wrapResultSet(this, ((PreparedStatement)this._stmt).executeQuery()); //查询
  } catch (SQLException var2) {
    this.handleException(var2);
    throw new AssertionError();
  }
}

oracle

说明hibernate的sql,已经被发送到oracle,而不是从缓存

public ResultSet executeQuery() throws SQLException {
  return this.preparedStatement.executeQuery();
}

回到应用,从结果集合取第一个数据

static Object uniqueElement(List list) throws NonUniqueResultException { //从集合里获取第一个数据
  int size = list.size();
  if (size == 0) {
    return null;
  } else {
    Object first = list.get(0);

    for(int i = 1; i < size; ++i) {
      if (list.get(i) != first) {
        throw new NonUniqueResultException(list.size());
      }
    }

    return first;
  }
}

调用栈

executeQuery:1495, OraclePreparedStatementWrapper (oracle.jdbc.driver)
executeQuery:96, DelegatingPreparedStatement (org.apache.commons.dbcp) [2]
executeQuery:96, DelegatingPreparedStatement (org.apache.commons.dbcp) [1]
getResultSet:208, AbstractBatcher (org.hibernate.jdbc)
getResultSet:1953, Loader (org.hibernate.loader)
doQuery:802, Loader (org.hibernate.loader)
doQueryAndInitializeNonLazyCollections:274, Loader (org.hibernate.loader)
doList:2542, Loader (org.hibernate.loader)
listIgnoreQueryCache:2276, Loader (org.hibernate.loader)
list:2271, Loader (org.hibernate.loader)
list:316, CustomLoader (org.hibernate.loader.custom)
listCustomQuery:1842, SessionImpl (org.hibernate.impl)
list:165, AbstractSessionImpl (org.hibernate.impl)
list:157, SQLQueryImpl (org.hibernate.impl)
listBySql:23, QueryHelper (hikefa.core.spring.util)
doInHibernate:1423, CatBaseDaoHibernateImpl$25 (com.xxx.log.integration.hibernate)
doExecute:406, HibernateTemplate (org.springframework.orm.hibernate3)
execute:339, HibernateTemplate (org.springframework.orm.hibernate3)
getListBySql:1421, CatBaseDaoHibernateImpl (com.xxx.log.integration.hibernate)
queryUrmtmFee:51, UrmtmFeeBaseDao (xxx.qrcode.register.dao.impl)
invoke:-1, UrmtmFeeBaseDao$$FastClassByCGLIB$$2b8e3f7d (xxx.qrcode.register.dao.impl)
invoke:204, MethodProxy (org.springframework.cglib.proxy)
invokeJoinpoint:698, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
proceed:150, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:80, MethodInvocationProceedingJoinPoint (org.springframework.aop.aspectj)
around:38, MethodExecTimeAspect (xxx.qrcode.register.util)
invoke:-1, GeneratedMethodAccessor258 (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:606, Method (java.lang.reflect)
invokeAdviceMethodWithGivenArgs:621, AbstractAspectJAdvice (org.springframework.aop.aspectj)
invokeAdviceMethod:610, AbstractAspectJAdvice (org.springframework.aop.aspectj)
invoke:65, AspectJAroundAdvice (org.springframework.aop.aspectj)
proceed:172, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:91, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
proceed:172, ReflectiveMethodInvocation (org.springframework.aop.framework)
intercept:631, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
queryUrmtmFee:-1, UrmtmFeeBaseDao$$EnhancerByCGLIB$$14ebc711 (xxx.qrcode.register.dao.impl)
getFee:219, QrcodeMerQueryServer (xxx.qrcode.register.remoteserver.impl)
queryMerchantInfo:75, QrcodeMerQueryServer (xxx.qrcode.register.remoteserver.impl)
invokeMethod:-1, Wrapper28 (com.alibaba.dubbo.common.bytecode)
doInvoke:47, JavassistProxyFactory$1 (com.alibaba.dubbo.rpc.proxy.javassist)
invoke:76, AbstractProxyInvoker (com.alibaba.dubbo.rpc.proxy)
invoke:52, DelegateProviderMetaDataInvoker (com.alibaba.dubbo.config.invoker)
invoke:56, InvokerWrapper (com.alibaba.dubbo.rpc.protocol)
invoke:11, AppNameAppendFilter (com.xxx.log.rpc.dubbo)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:62, ExceptionFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:42, TimeoutFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:60, ExecuteLimitFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:75, MonitorFilter (com.alibaba.dubbo.monitor.support)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:78, TraceFilter (com.alibaba.dubbo.rpc.protocol.dubbo.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:84, AccessLogExtFilter (xxx.qrcode.common.filter.dubbo)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:82, CatTransaction (com.xxx.log.rpc.dubbo)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:73, ContextFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:138, GenericFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:38, ClassLoaderFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:38, EchoFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
reply:104, DubboProtocol$1 (com.alibaba.dubbo.rpc.protocol.dubbo)
handleRequest:96, HeaderExchangeHandler (com.alibaba.dubbo.remoting.exchange.support.header)
received:173, HeaderExchangeHandler (com.alibaba.dubbo.remoting.exchange.support.header)
received:51, DecodeHandler (com.alibaba.dubbo.remoting.transport)
run:57, ChannelEventRunnable (com.alibaba.dubbo.remoting.transport.dispatcher)
runWorker:1145, ThreadPoolExecutor (java.util.concurrent)
run:615, ThreadPoolExecutor$Worker (java.util.concurrent)
run:745, Thread (java.lang)

总结

1、每个sql都被发送到了oracle,而不是从hibernate缓存读写数据,最后service类的业务方法结束的时候,提交事务,oracle数据更新永久生效,即对其他事务都生效可见。

调试源码的过程中,走到了oracle,也证明sql被发送到了oracle,即是从oracle数据库读写数据,而不是从hibernate缓存。

2、流程
应用业务代码(service类的业务方法,包含多个sql)——》spring事务——》dao的方法(单个sql)——》hibernate——》连接池dbcp——》jdbc-oracle——》数据库oracle。

每一层只管一件事,
1)spring事务,只负责事务开始和提交。
2)hibernate,就是会话连接,本质其实就是jdbc的Connection对象。
3)连接池dbcp,负责获取数据库连接。

然后,每一层执行的时候,都是由上一层委托给下一层。