public void setRollbackOnly() {
    TransactionID txId = currentTransactionIdThreadLocal.get();
    if (txId == null) {
      throw new TransactionException("no transaction started");
    }

    TransactionContext currentTx = contextMap.get(txId);

    currentTx.setRollbackOnly(true);
  }
  public void begin(int transactionTimeout) {
    TransactionID txId = currentTransactionIdThreadLocal.get();
    if (txId != null) {
      throw new TransactionException("transaction already started");
    }

    TransactionContext newTx =
        new TransactionContext(transactionTimeout, transactionIDFactory.createTransactionID());
    contextMap.put(newTx.getTransactionId(), newTx);
    currentTransactionIdThreadLocal.set(newTx.getTransactionId());

    MDC.put(MDC_KEY, newTx.getTransactionId().toString());
    LOG.debug("begun transaction {}", newTx.getTransactionId());
  }
  public void rollback() {
    TransactionID txId = currentTransactionIdThreadLocal.get();
    if (txId == null) {
      throw new TransactionException("no transaction started");
    }

    TransactionContext currentTx = contextMap.get(txId);

    try {
      currentTx.rollback();
    } finally {
      contextMap.remove(txId);
      currentTransactionIdThreadLocal.remove();
      MDC.remove(MDC_KEY);
    }
  }
  public void commit(boolean ignoreTimeout) {
    TransactionID txId = currentTransactionIdThreadLocal.get();
    if (txId == null) {
      throw new TransactionException("no transaction started");
    }

    TransactionContext currentTx = contextMap.get(txId);

    try {
      currentTx.commit(ignoreTimeout);
    } finally {
      contextMap.remove(txId);
      currentTransactionIdThreadLocal.remove();
      MDC.remove(MDC_KEY);
    }
  }