Java tutorial
/** * 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; } }