All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.firefly.db.ThreadLocalTransactionalManager Maven / Gradle / Ivy

package com.firefly.db;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @author Pengtao Qiu
 */
public class ThreadLocalTransactionalManager implements TransactionalManager {

    private final static Logger log = LoggerFactory.getLogger("firefly-system");

    private final ThreadLocal transaction = new ThreadLocal<>();
    private final DataSource dataSource;

    public ThreadLocalTransactionalManager(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public void beginTransaction() {
        getTransaction().beginTransaction();
    }

    @Override
    public Connection getConnection() {
        if (isTransactionBegin()) {
            return getTransaction().getConnection();
        } else {
            return getConnectionFromDataSource();
        }
    }

    @Override
    public void commit() {
        checkTransactionBegin();
        getTransaction().commit();
    }

    @Override
    public void rollback() {
        checkTransactionBegin();
        getTransaction().rollback();
    }

    @Override
    public void endTransaction() {
        checkTransactionBegin();
        getTransaction().endTransaction();
    }

    @Override
    public boolean isTransactionBegin() {
        return transaction.get() != null;
    }

    private void checkTransactionBegin() {
        if (!isTransactionBegin()) {
            throw new DBException("the transaction is not begin");
        }
    }

    private Connection getConnectionFromDataSource() {
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            log.error("get connection exception", e);
            throw new DBException(e);
        }
    }


    private Transaction getTransaction() {
        Transaction t = transaction.get();
        if (t == null) {
            t = new Transaction();
            transaction.set(t);
        }
        return t;
    }

    enum Status {
        INIT, START, COMMIT, ROLLBACK, END
    }

    class Transaction {
        private Connection connection;
        private Status status = Status.INIT;
        private int count = 0;

        synchronized void beginTransaction() {
            if (status == Status.INIT) {
                connection = getConnectionFromDataSource();
                setAutoCommit(connection, false);
                status = Status.START;
            }
            count++;
            log.debug("begin transaction {}", count);
        }

        synchronized Connection getConnection() {
            check();
            return connection;
        }

        synchronized void rollback() {
            check();
            status = Status.ROLLBACK;
        }

        synchronized void commit() {
            check();
            if (status != Status.ROLLBACK) {
                status = Status.COMMIT;
            }
        }

        private synchronized void check() {
            if (status == Status.INIT) {
                throw new IllegalStateException("The transaction has not started, " + status);
            }
            if (status == Status.END) {
                throw new IllegalStateException("The transaction has ended, " + status);
            }
        }

        synchronized void endTransaction() {
            count--;
            if (count == 0) {
                switch (status) {
                    case START:
                    case COMMIT:
                        commit(connection);
                        break;
                    case ROLLBACK:
                        rollback(connection);
                        break;
                    default:
                        break;
                }
                setAutoCommit(connection, true);
                close(connection);
                transaction.set(null);
                status = Status.END;
            }
            log.debug("end transaction {}", count);
        }

        private void setAutoCommit(Connection connection, boolean autoCommit) {
            try {
                connection.setAutoCommit(autoCommit);
            } catch (SQLException e) {
                log.error("set auto commit exception", e);
            }
        }

        private void rollback(Connection connection) {
            try {
                connection.rollback();
            } catch (SQLException e) {
                log.error("transaction rollback exception", e);
                throw new DBException(e);
            }
        }

        private void commit(Connection connection) {
            try {
                connection.commit();
            } catch (SQLException e) {
                log.error("commit exception", e);
            }
        }

        private void close(Connection connection) {
            try {
                connection.close();
            } catch (SQLException e) {
                log.error("close connection exception", e);
            }
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy