@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String strArgs;
    try {
      strArgs = args == null ? "" : StringUtils.join(Arrays.asList(args), ",");
    } catch (Exception e) {
      LOG.warn("Error while trying to stringify the method arguments.", e);
      strArgs = "unknown";
    }
    String callerId = method.getName() + "(" + strArgs + ")";
    SqlRetry retry = method.getAnnotation(SqlRetry.class);
    Transactional transactional = method.getAnnotation(Transactional.class);

    ThrowingSupplier functionToCall = () -> {
      try {
        return method.invoke(interfaceObject, args);
      } catch (InvocationTargetException | UndeclaredThrowableException e) {
        throw e.getCause();
      }
    };

    if (transactional != null) {
      ThrowingSupplier toCall = functionToCall;
      functionToCall = () -> {
        LOG.debug("Invoking method within transactional context: {}", callerId);
        TransactionContext context = null;
        try {
          jdbcResource.bindDataSource(transactional);
          context = jdbcResource.getTransactionManager().getNewTransaction(transactional.propagation().value());
          Object result = toCall.execute();
          LOG.debug("Successfull method invocation within transactional context: {}, going to commit.", callerId);
          if (context.isRollbackOnly()) {
            jdbcResource.getTransactionManager().rollback(context);
          } else if (!context.isCompleted()) {
            jdbcResource.getTransactionManager().commit(context);
          }
          return result;
        } catch (RollbackException e) {
          if (context != null && !context.isCompleted()) {
            jdbcResource.getTransactionManager().rollback(context);
          }          
          return e.getResult();
        } catch (Exception e) {
          if (context != null) {
            if (transactional.noRollbackFor().length > 0 || transactional.noRollbackForClassName().length > 0) {
              if (Arrays.stream(transactional.noRollbackFor()).anyMatch(ex -> ex.isInstance(e)) ||
                  Arrays.stream(transactional.noRollbackForClassName()).anyMatch(exName -> exName.equals(e.getClass().getName()))) {
                jdbcResource.getTransactionManager().commit(context);
              } else {
                jdbcResource.getTransactionManager().rollback(context);
              }
            } else if (transactional.rollbackFor().length > 0 || transactional.rollbackForClassName().length > 0) {
              if (Arrays.stream(transactional.rollbackFor()).anyMatch(ex -> ex.isInstance(e)) ||
                  Arrays.stream(transactional.rollbackForClassName()).anyMatch(exName -> exName.equals(e.getClass().getName()))) {
                jdbcResource.getTransactionManager().rollback(context);
              } else {
                jdbcResource.getTransactionManager().commit(context);                
              }
            } else {
              jdbcResource.getTransactionManager().rollback(context);
            }
          }
          throw e;
        } finally {
          jdbcResource.unbindDataSource();
        }
      };
    }

    if (retry != null) {
      SqlRetryCallProperties properties = new SqlRetryCallProperties()
          .withCallerId(callerId)
          .withLockInternally(retry.lockInternally())
          .withRetryOnDuplicateKey(retry.retryOnDuplicateKey());
      ThrowingSupplier toCall = functionToCall;
      SqlRetryFunction<Object> retryWrapper = () -> {
        try {
          LOG.debug("Invoking method within retry context: {}", callerId);
          Object result = toCall.execute();
          LOG.debug("Successfull method invocation within retry context: {}", callerId);
          return result;
        } catch (IllegalAccessException | InvocationTargetException | UndeclaredThrowableException e) {
          if (e.getCause() instanceof TException) {
            throw (TException) e.getCause();
          } else if (e.getCause() instanceof RuntimeException) {
            throw (RuntimeException) e.getCause();
          } else {
            throw new RuntimeException(e);
          }
        } catch (TException | DataAccessException e) {
          throw e;
        } catch (Throwable e) {          
          if (e instanceof RuntimeException) {
            throw (RuntimeException) e;
          } else if (e.getCause() instanceof RuntimeException) {
              throw (RuntimeException)e.getCause();
          } else {
            throw new RuntimeException(e);
          }
        }
      };
      return sqlRetryHandler.executeWithRetry(properties, retryWrapper);
    } else {
      LOG.debug("Invoking method without retry context: {}", callerId);
      Object result = functionToCall.execute();
      LOG.debug("Successfull method invocation without retry context: {}", callerId);
      return result;
    }
  }
Gets the proxy interface for the given {@link TxnStore}.

@param sqlRetryHandler Responsible to re-execute the methods in case of failure.
@param interfaceObject The real object to proxy.
@return Returns the proxy object capable of retrying the failed calls automatically and transparently.
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/txn/TransactionalRetryProxy.java