Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ebean-api/src/main/java/io/ebean/DatabaseBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ public interface DatabaseBuilder {

/**
* Build and return the Database instance.
* <p>
* When {@link #setRegister(boolean)} is set to true, and a database with the same
* name is already registered, this may return the existing registered database
* rather than creating a new one.
*/
Database build();

Expand Down
28 changes: 22 additions & 6 deletions ebean-api/src/main/java/io/ebean/DatabaseFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import java.util.concurrent.locks.ReentrantLock;

import static java.lang.System.Logger.Level.WARNING;

/**
* Creates Database instances.
* <p>
Expand Down Expand Up @@ -61,7 +63,11 @@ public static Database create(String name) {

/**
* Create using the DatabaseConfig object to configure the database.
*
* <p>
* When the configuration has {@link DatabaseBuilder.Settings#isRegister()} set to true,
* and a database with the same name is already registered, this returns the existing
* registered database rather than creating a new one.
* </p>
* <pre>{@code
*
* DatabaseConfig config = new DatabaseConfig();
Expand All @@ -76,18 +82,28 @@ public static Database create(DatabaseBuilder builder) {
lock.lock();
try {
var config = builder.settings();
if (config.getName() == null) {
var name = config.getName();
if (name == null) {
throw new PersistenceException("The name is null (it is required)");
}
if (config.isRegister()) {
// We're explicitly creating a database to be registered, so avoid
// triggering DbContext static initialisation to auto-create a default one.
DbPrimary.setSkip(true);
Database existing = DbContext.getInstance().getRegistered(name);
if (existing != null) {
EbeanVersion.log.log(WARNING, "Using existing database with name:{0}", name);
return existing;
}
}
Database server = createInternal(config);
if (config.isRegister()) {
if (config.isDefaultServer()) {
if (defaultServerName != null && !defaultServerName.equals(config.getName())) {
throw new IllegalStateException("Registering [" + config.getName() + "] as the default server but [" + defaultServerName + "] is already registered as the default");
if (defaultServerName != null && !defaultServerName.equals(name)) {
throw new IllegalStateException("Registering [" + name + "] as the default server but [" + defaultServerName + "] is already registered as the default");
}
defaultServerName = config.getName();
defaultServerName = name;
}
DbPrimary.setSkip(true);
DbContext.getInstance().register(server, config.isDefaultServer());
}
return server;
Expand Down
7 changes: 7 additions & 0 deletions ebean-api/src/main/java/io/ebean/DbContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import io.ebean.datasource.DataSourceConfigurationException;

import jakarta.persistence.PersistenceException;
import org.jspecify.annotations.Nullable;

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
Expand Down Expand Up @@ -75,6 +77,11 @@ Database getDefault() {
return defaultDatabase;
}

@Nullable
Database getRegistered(String name) {
return concMap.get(name);
}

/**
* Return the database by name.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import static org.assertj.core.api.Assertions.assertThat;

Expand Down Expand Up @@ -81,6 +82,59 @@ public void test() throws InterruptedException {
restartedServer.shutdown(true, false);
}

@Test
public void create_registeredDatabase_twice_returnsExistingInstance() {

DatabaseBuilder config = new DatabaseConfig();
config.setName("h2");
config.loadFromProperties();
config.setName("dup-" + System.nanoTime());
config.setDdlGenerate(false);
config.setDdlRun(false);
config.setDdlExtra(false);
config.setDefaultServer(false);
config.setRegister(true);
config.addClass(UTDetail.class);

AtomicInteger startupCount = new AtomicInteger();
config.addServerConfigStartup(serverConfig -> startupCount.incrementAndGet());

Database db = DatabaseFactory.create(config);
Database existing = DatabaseFactory.create(config);

assertThat(existing).isSameAs(db);
assertThat(startupCount.get()).isEqualTo(1);

db.shutdown(true, false);
}

@Test
public void create_unregisteredDatabase_twice_returnsDifferentInstances() {

DatabaseBuilder config = new DatabaseConfig();
config.setName("h2");
config.loadFromProperties();
config.setName("dup-unregistered-" + System.nanoTime());
config.setDdlGenerate(false);
config.setDdlRun(false);
config.setDdlExtra(false);
config.setDefaultServer(false);
config.setRegister(false);
config.addClass(UTDetail.class);

AtomicInteger startupCount = new AtomicInteger();
config.addServerConfigStartup(serverConfig -> startupCount.incrementAndGet());

Database db = DatabaseFactory.create(config);
Database other = DatabaseFactory.create(config);

assertThat(other).isNotSameAs(db);
assertThat(startupCount.get()).isEqualTo(2);

db.shutdown(true, false);
other.shutdown(true, false);
}

public static class OnStartup implements ServerConfigStartup {

DatabaseBuilder calledWithConfig;
Expand Down
Loading