/**
   * Return whether the given Redis connection is transactional, that is, bound to the current
   * thread by Spring's transaction facilities.
   *
   * @param conn Redis connection to check
   * @param connFactory Redis connection factory that the connection was created with
   * @return whether the connection is transactional or not
   */
  public static boolean isConnectionTransactional(
      RedisConnection conn, RedisConnectionFactory connFactory) {
    if (connFactory == null) {
      return false;
    }
    RedisConnectionHolder connHolder =
        (RedisConnectionHolder) TransactionSynchronizationManager.getResource(connFactory);

    return (connHolder != null && conn == connHolder.getConnection());
  }
    @Override
    public void afterCompletion(int status) {

      try {
        switch (status) {
          case TransactionSynchronization.STATUS_COMMITTED:
            connection.exec();
            break;

          case TransactionSynchronization.STATUS_ROLLED_BACK:
          case TransactionSynchronization.STATUS_UNKNOWN:
          default:
            connection.discard();
        }
      } finally {

        if (log.isDebugEnabled()) {
          log.debug("Closing bound connection after transaction completed with " + status);
        }

        connHolder.setTransactionSyncronisationActive(false);
        connection.close();
        TransactionSynchronizationManager.unbindResource(factory);
      }
    }
  private static void potentiallyRegisterTransactionSynchronisation(
      RedisConnectionHolder connHolder, final RedisConnectionFactory factory) {

    if (isActualNonReadonlyTransactionActive()) {

      if (!connHolder.isTransactionSyncronisationActive()) {
        connHolder.setTransactionSyncronisationActive(true);

        RedisConnection conn = connHolder.getConnection();
        conn.multi();

        TransactionSynchronizationManager.registerSynchronization(
            new RedisTransactionSynchronizer(connHolder, conn, factory));
      }
    }
  }
  /**
   * Gets a Redis connection. Is aware of and will return any existing corresponding connections
   * bound to the current thread, for example when using a transaction manager. Will create a new
   * Connection otherwise, if {@code allowCreate} is <tt>true</tt>.
   *
   * @param factory connection factory for creating the connection
   * @param allowCreate whether a new (unbound) connection should be created when no connection can
   *     be found for the current thread
   * @param bind binds the connection to the thread, in case one was created
   * @param enableTransactionSupport
   * @return an active Redis connection
   */
  public static RedisConnection doGetConnection(
      RedisConnectionFactory factory,
      boolean allowCreate,
      boolean bind,
      boolean enableTransactionSupport) {

    Assert.notNull(factory, "No RedisConnectionFactory specified");

    RedisConnectionHolder connHolder =
        (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory);

    if (connHolder != null) {
      if (enableTransactionSupport) {
        potentiallyRegisterTransactionSynchronisation(connHolder, factory);
      }
      return connHolder.getConnection();
    }

    if (!allowCreate) {
      throw new IllegalArgumentException("No connection found and allowCreate = false");
    }

    if (log.isDebugEnabled()) {
      log.debug("Opening RedisConnection");
    }

    RedisConnection conn = factory.getConnection();

    if (bind) {

      RedisConnection connectionToBind = conn;
      if (enableTransactionSupport && isActualNonReadonlyTransactionActive()) {
        connectionToBind = createConnectionProxy(conn, factory);
      }

      connHolder = new RedisConnectionHolder(connectionToBind);

      TransactionSynchronizationManager.bindResource(factory, connHolder);
      if (enableTransactionSupport) {
        potentiallyRegisterTransactionSynchronisation(connHolder, factory);
      }

      return connHolder.getConnection();
    }

    return conn;
  }
  /**
   * Unbinds and closes the connection (if any) associated with the given factory.
   *
   * @param factory Redis factory
   */
  public static void unbindConnection(RedisConnectionFactory factory) {

    RedisConnectionHolder connHolder =
        (RedisConnectionHolder) TransactionSynchronizationManager.unbindResourceIfPossible(factory);

    if (connHolder != null) {
      if (connHolder.isTransactionSyncronisationActive()) {
        if (log.isDebugEnabled()) {
          log.debug("Redis Connection will be closed when outer transaction finished.");
        }
      } else {
        if (log.isDebugEnabled()) {
          log.debug("Closing bound connection.");
        }
        RedisConnection connection = connHolder.getConnection();
        connection.close();
      }
    }
  }
  /**
   * Closes the given connection, created via the given factory if not managed externally (i.e. not
   * bound to the thread).
   *
   * @param conn the Redis connection to close
   * @param factory the Redis factory that the connection was created with
   */
  public static void releaseConnection(RedisConnection conn, RedisConnectionFactory factory) {

    if (conn == null) {
      return;
    }

    RedisConnectionHolder connHolder =
        (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory);

    if (connHolder != null && connHolder.isTransactionSyncronisationActive()) {
      if (log.isDebugEnabled()) {
        log.debug("Redis Connection will be closed when transaction finished.");
      }
      return;
    }

    // Only release non-transactional/non-bound connections.
    if (!isConnectionTransactional(conn, factory)) {
      if (log.isDebugEnabled()) {
        log.debug("Closing Redis Connection");
      }
      conn.close();
    }
  }