com.alibaba.cobar.client.transaction.MultipleDataSourcesTransactionManager.java Source code

Java tutorial

Introduction

Here is the source code for com.alibaba.cobar.client.transaction.MultipleDataSourcesTransactionManager.java

Source

/**
 * Copyright 1999-2011 Alibaba Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.cobar.client.transaction;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;

import com.alibaba.cobar.client.datasources.ICobarDataSourceService;

/**
 * use {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy} to wrap all of the data sources we
 * may use in TransactionManager and DAOs. {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy}
 * will only fetch a connection when first statement get executed. So even we
 * start transaction on such data sources which are wrapped by
 * {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy}, there is no performance penalty at
 * not.
 *
 *
 *
 * @author fujohnwang
 * @since 1.0, Jan 28, 2010
 */
public class MultipleDataSourcesTransactionManager extends AbstractPlatformTransactionManager
        implements InitializingBean {
    protected transient Logger logger = org.slf4j.LoggerFactory
            .getLogger(MultipleDataSourcesTransactionManager.class);

    private static final long serialVersionUID = 4712923770419532385L;

    private ICobarDataSourceService cobarDataSourceService;
    private List<PlatformTransactionManager> transactionManagers = new ArrayList<PlatformTransactionManager>();

    @Override
    protected Object doGetTransaction() throws TransactionException {
        return new ArrayList<DefaultTransactionStatus>();
    }

    /**
     * We need to disable transaction synchronization so that the shared
     * transaction synchronization state will not collide with each other. BUT,
     * for LOB creators to use, we have to pay attention here:
     * <ul>
     * <li>if the LOB creator use standard preparedStatement methods, this
     * transaction synchronization setting is OK;</li>
     * <li>if the LOB creator don't use standard PS methods, you have to find
     * other way to make sure the resources your LOB creator used should be
     * cleaned up after the transaction.</li>
     * </ul>
     */
    @Override
    protected void doBegin(Object transactionObject, TransactionDefinition transactionDefinition)
            throws TransactionException {
        @SuppressWarnings("unchecked")
        List<DefaultTransactionStatus> list = (List<DefaultTransactionStatus>) transactionObject;
        for (PlatformTransactionManager transactionManager : transactionManagers) {
            DefaultTransactionStatus element = (DefaultTransactionStatus) transactionManager
                    .getTransaction(transactionDefinition);
            list.add(element);
        }
    }

    @Override
    protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
        @SuppressWarnings("unchecked")
        List<DefaultTransactionStatus> list = (List<DefaultTransactionStatus>) status.getTransaction();

        logger.info("prepare to commit transactions on multiple data sources.");
        Validate.isTrue(list.size() <= this.getTransactionManagers().size());

        TransactionException lastException = null;
        for (int i = list.size() - 1; i >= 0; i--) {
            PlatformTransactionManager transactionManager = this.getTransactionManagers().get(i);
            TransactionStatus localTransactionStatus = list.get(i);

            try {
                transactionManager.commit(localTransactionStatus);
            } catch (TransactionException e) {
                lastException = e;
                logger.error("Error in commit", e);

            }
        }
        if (lastException != null) {
            throw lastException;
            // Rollback will ensue as long as rollbackOnCommitFailure=true
        }

    }

    @Override
    protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
        @SuppressWarnings("unchecked")
        List<DefaultTransactionStatus> list = (List<DefaultTransactionStatus>) status.getTransaction();

        logger.info("prepare to rollback transactions on multiple data sources.");
        Validate.isTrue(list.size() <= this.getTransactionManagers().size());

        TransactionException lastException = null;
        for (int i = list.size() - 1; i >= 0; i--) {
            PlatformTransactionManager transactionManager = this.getTransactionManagers().get(i);
            TransactionStatus localTransactionStatus = list.get(i);

            try {
                transactionManager.rollback(localTransactionStatus);
            } catch (TransactionException e) {
                // Log exception and try to complete rollback
                lastException = e;
                logger.error("error occured when rolling back the transaction. \n{}", e);
            }
        }

        if (lastException != null) {
            throw lastException;
        }
    }

    public void setCobarDataSourceService(ICobarDataSourceService cobarDataSourceService) {
        this.cobarDataSourceService = cobarDataSourceService;
    }

    public ICobarDataSourceService getCobarDataSourceService() {
        return cobarDataSourceService;
    }

    public void afterPropertiesSet() throws Exception {
        Validate.notNull(cobarDataSourceService);
        for (DataSource dataSource : getCobarDataSourceService().getDataSources().values()) {
            PlatformTransactionManager txManager = this.createTransactionManager(dataSource);
            getTransactionManagers().add(txManager);
        }
        //Collections.reverse(getTransactionManagers());
    }

    protected PlatformTransactionManager createTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    public List<PlatformTransactionManager> getTransactionManagers() {
        return transactionManagers;
    }

}