diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java index 5213ef5cd..182015244 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java @@ -78,29 +78,36 @@ public abstract class MongoDbUtils { private static DB doGetDB(Mongo mongo, String databaseName, UserCredentials credentials, boolean allowCreate) { DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo); + if (dbHolder != null && !dbHolder.isEmpty()) { - // pre-bound Mongo DB + DB db = null; + if (TransactionSynchronizationManager.isSynchronizationActive() && dbHolder.doesNotHoldNonDefaultDB()) { - // Spring transaction management is active -> - db = dbHolder.getDB(); + + db = dbHolder.getDB(databaseName); + if (db != null && !dbHolder.isSynchronizedWithTransaction()) { - LOGGER.debug("Registering Spring transaction synchronization for existing Mongo DB"); + + LOGGER.debug("Registering Spring transaction synchronization for existing MongoDB {}.", databaseName); + TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(dbHolder, mongo)); dbHolder.setSynchronizedWithTransaction(true); } } + if (db != null) { return db; } } - LOGGER.trace("Getting Mongo Database name=[" + databaseName + "]"); - DB db = mongo.getDB(databaseName); + LOGGER.debug("Getting Mongo Database name=[{}]", databaseName); + DB db = mongo.getDB(databaseName); boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword(); + if (credentialsGiven && !db.isAuthenticated()) { - // Note, can only authenticate once against the same com.mongodb.DB object. + String username = credentials.getUsername(); String password = credentials.hasPassword() ? credentials.getPassword() : null; @@ -113,16 +120,20 @@ public abstract class MongoDbUtils { // Use same Session for further Mongo actions within the transaction. // Thread object will get removed by synchronization at transaction completion. if (TransactionSynchronizationManager.isSynchronizationActive()) { - // We're within a Spring-managed transaction, possibly from JtaTransactionManager. - LOGGER.debug("Registering Spring transaction synchronization for new Hibernate Session"); + + LOGGER.debug("Registering Spring transaction synchronization for MongoDB instance {}.", databaseName); + DbHolder holderToUse = dbHolder; + if (holderToUse == null) { - holderToUse = new DbHolder(db); + holderToUse = new DbHolder(databaseName, db); } else { - holderToUse.addDB(db); + holderToUse.addDB(databaseName, db); } + TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo)); holderToUse.setSynchronizedWithTransaction(true); + if (holderToUse != dbHolder) { TransactionSynchronizationManager.bindResource(mongo, holderToUse); } @@ -146,6 +157,7 @@ public abstract class MongoDbUtils { * @return whether the DB is transactional */ public static boolean isDBTransactional(DB db, Mongo mongo) { + if (mongo == null) { return false; } @@ -159,6 +171,7 @@ public abstract class MongoDbUtils { * @param db the DB to close (may be null) */ public static void closeDB(DB db) { + if (db != null) { LOGGER.debug("Closing Mongo DB object"); try { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsUnitTests.java new file mode 100644 index 000000000..571e82b92 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsUnitTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012 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 + * + * 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 org.springframework.data.mongodb.core; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import com.mongodb.DB; +import com.mongodb.Mongo; + +/** + * Unit tests for {@link MongoDbUtils}. + * + * @author Oliver Gierke + */ +public class MongoDbUtilsUnitTests { + + Mongo mongo; + + @Before + public void setUp() throws Exception { + this.mongo = new Mongo(); + TransactionSynchronizationManager.initSynchronization(); + } + + @After + public void tearDown() { + + for (Object key : TransactionSynchronizationManager.getResourceMap().keySet()) { + TransactionSynchronizationManager.unbindResource(key); + } + + TransactionSynchronizationManager.clearSynchronization(); + } + + @Test + public void returnsNewInstanceForDifferentDatabaseName() { + + DB first = MongoDbUtils.getDB(mongo, "first"); + assertThat(first, is(notNullValue())); + assertThat(MongoDbUtils.getDB(mongo, "first"), is(first)); + + DB second = MongoDbUtils.getDB(mongo, "second"); + assertThat(second, is(not(first))); + assertThat(MongoDbUtils.getDB(mongo, "second"), is(second)); + } +}