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

org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2018 the original author or authors.
 *
 * 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
 *
 *      https://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 org.springframework.jdbc.datasource.lookup;

import org.springframework.core.Constants;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationManager;

/**
 * DataSource that routes to one of various target DataSources based on the
 * current transaction isolation level. The target DataSources need to be
 * configured with the isolation level name as key, as defined on the
 * {@link org.springframework.transaction.TransactionDefinition TransactionDefinition interface}.
 *
 * 

This is particularly useful in combination with JTA transaction management * (typically through Spring's {@link org.springframework.transaction.jta.JtaTransactionManager}). * Standard JTA does not support transaction-specific isolation levels. Some JTA * providers support isolation levels as a vendor-specific extension (e.g. WebLogic), * which is the preferred way of addressing this. As alternative (e.g. on WebSphere), * the target database can be represented through multiple JNDI DataSources, each * configured with a different isolation level (for the entire DataSource). * The present DataSource router allows to transparently switch to the * appropriate DataSource based on the current transaction's isolation level. * *

The configuration can for example look like this, assuming that the target * DataSources are defined as individual Spring beans with names * "myRepeatableReadDataSource", "mySerializableDataSource" and "myDefaultDataSource": * *

 * <bean id="dataSourceRouter" class="org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter">
 *   <property name="targetDataSources">
 *     <map>
 *       <entry key="ISOLATION_REPEATABLE_READ" value-ref="myRepeatableReadDataSource"/>
 *       <entry key="ISOLATION_SERIALIZABLE" value-ref="mySerializableDataSource"/>
 *     </map>
 *   </property>
 *   <property name="defaultTargetDataSource" ref="myDefaultDataSource"/>
 * </bean>
* * Alternatively, the keyed values can also be data source names, to be resolved * through a {@link #setDataSourceLookup DataSourceLookup}: by default, JNDI * names for a standard JNDI lookup. This allows for a single concise definition * without the need for separate DataSource bean definitions. * *
 * <bean id="dataSourceRouter" class="org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter">
 *   <property name="targetDataSources">
 *     <map>
 *       <entry key="ISOLATION_REPEATABLE_READ" value="java:comp/env/jdbc/myrrds"/>
 *       <entry key="ISOLATION_SERIALIZABLE" value="java:comp/env/jdbc/myserds"/>
 *     </map>
 *   </property>
 *   <property name="defaultTargetDataSource" value="java:comp/env/jdbc/mydefds"/>
 * </bean>
* * Note: If you are using this router in combination with Spring's * {@link org.springframework.transaction.jta.JtaTransactionManager}, * don't forget to switch the "allowCustomIsolationLevels" flag to "true". * (By default, JtaTransactionManager will only accept a default isolation level * because of the lack of isolation level support in standard JTA itself.) * *
 * <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
 *   <property name="allowCustomIsolationLevels" value="true"/>
 * </bean>
* * @author Juergen Hoeller * @since 2.0.1 * @see #setTargetDataSources * @see #setDefaultTargetDataSource * @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_UNCOMMITTED * @see org.springframework.transaction.TransactionDefinition#ISOLATION_READ_COMMITTED * @see org.springframework.transaction.TransactionDefinition#ISOLATION_REPEATABLE_READ * @see org.springframework.transaction.TransactionDefinition#ISOLATION_SERIALIZABLE * @see org.springframework.transaction.jta.JtaTransactionManager */ public class IsolationLevelDataSourceRouter extends AbstractRoutingDataSource { /** Constants instance for TransactionDefinition. */ private static final Constants constants = new Constants(TransactionDefinition.class); /** * Supports Integer values for the isolation level constants * as well as isolation level names as defined on the * {@link org.springframework.transaction.TransactionDefinition TransactionDefinition interface}. */ @Override protected Object resolveSpecifiedLookupKey(Object lookupKey) { if (lookupKey instanceof Integer) { return lookupKey; } else if (lookupKey instanceof String) { String constantName = (String) lookupKey; if (!constantName.startsWith(DefaultTransactionDefinition.PREFIX_ISOLATION)) { throw new IllegalArgumentException("Only isolation constants allowed"); } return constants.asNumber(constantName); } else { throw new IllegalArgumentException( "Invalid lookup key - needs to be isolation level Integer or isolation level name String: " + lookupKey); } } @Override @Nullable protected Object determineCurrentLookupKey() { return TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy