public void begin(Map<String, Serializable> settings) throws ClickHouseException {
        log.debug("Begin %s", this);
        int currentState = state.get();
        if (currentState == ACTIVE) {
            log.debug("Skip since the transaction has been started already");
            return;
        } else if (currentState == FAILED) {
            throw new ClickHouseTransactionException(
                    "Cannot restart a failed transaction - please roll back or create a new transaction",
                    this);
        }

        try {
            id.updateAndGet(x -> {
                boolean success = false;
                XID txId = null;
                try {
                    // reuse existing transaction if any
                    txId = XID.of(issue(QUERY_SELECT_TX_ID, false, Collections.emptyMap()).getValue(0).asTuple());
                    if (XID.EMPTY.equals(txId)) {
                        issue("BEGIN TRANSACTION", true, settings);
                        txId = XID.of(issue(QUERY_SELECT_TX_ID).getValue(0).asTuple());
                    }

                    if (XID.EMPTY.equals(txId)) {
                        throw new ClickHouseTransactionException(
                                ClickHouseTransactionException.ERROR_UNKNOWN_STATUS_OF_TRANSACTION,
                                "Failed to start new transaction", this);
                    }
                    success = state.compareAndSet(currentState, ACTIVE);
                    return txId;
                } catch (ClickHouseException e) {
                    throw new IllegalStateException(e);
                } finally {
                    if (txId != null && !success) {
                        state.compareAndSet(currentState, FAILED);
                    }
                }
            });
            log.debug("Began new transaction: %s", this);
        } catch (IllegalStateException e) {
            if (e.getCause() instanceof ClickHouseException) {
                throw (ClickHouseException) e.getCause();
            } else {
                throw e;
            }
        }
    }
Starts a new transaction with optional server settings. It's a no-op when
calling against an {@link #ACTIVE} transaction.

@param settings optional server settings
@throws ClickHouseException when failed to begin new transaction
clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseTransaction.java