0
# Multi-Database Management
1
2
API for managing multiple database configurations in a single application, with named database support and lifecycle management.
3
4
## Capabilities
5
6
### DBApi Interface (Scala)
7
8
Primary interface for managing multiple databases in Scala.
9
10
```scala { .api }
11
trait DBApi {
12
/** All configured databases */
13
def databases(): Seq[Database]
14
/** Get database with given configuration name */
15
def database(name: String): Database
16
/** Shutdown all databases, releasing resources */
17
def shutdown(): Unit
18
}
19
```
20
21
**Usage Examples:**
22
23
```scala
24
import play.api.db._
25
import javax.inject.Inject
26
27
class MultiDbController @Inject()(dbApi: DBApi) {
28
// Access specific databases by name
29
def getUserData(userId: Long) = {
30
val userDb = dbApi.database("users")
31
val profileDb = dbApi.database("profiles")
32
33
userDb.withConnection { implicit conn =>
34
// Query user data
35
val stmt = conn.prepareStatement("SELECT name FROM users WHERE id = ?")
36
stmt.setLong(1, userId)
37
val rs = stmt.executeQuery()
38
// ... process results
39
}
40
}
41
42
// Iterate over all databases
43
def performMaintenance() = {
44
dbApi.databases().foreach { db =>
45
println(s"Performing maintenance on database: ${db.name}")
46
db.withConnection { implicit conn =>
47
// Maintenance operations
48
conn.prepareStatement("ANALYZE").execute()
49
}
50
}
51
}
52
53
// Graceful shutdown
54
def cleanup() = {
55
dbApi.shutdown()
56
}
57
}
58
```
59
60
### DBApi Interface (Java)
61
62
Primary interface for managing multiple databases in Java.
63
64
```java { .api }
65
public interface DBApi {
66
/** @return all configured databases */
67
List<Database> getDatabases();
68
/** Get database with given configuration name */
69
Database getDatabase(String name);
70
/** Shutdown all databases, releasing resources */
71
void shutdown();
72
}
73
```
74
75
**Usage Examples:**
76
77
```java
78
import play.db.*;
79
import javax.inject.Inject;
80
import java.util.List;
81
82
public class MultiDbController {
83
private final DBApi dbApi;
84
85
@Inject
86
public MultiDbController(DBApi dbApi) {
87
this.dbApi = dbApi;
88
}
89
90
// Access specific databases by name
91
public void processUserData(long userId) {
92
Database userDb = dbApi.getDatabase("users");
93
Database logDb = dbApi.getDatabase("logs");
94
95
userDb.withConnection(connection -> {
96
PreparedStatement stmt = connection.prepareStatement("SELECT email FROM users WHERE id = ?");
97
stmt.setLong(1, userId);
98
ResultSet rs = stmt.executeQuery();
99
// ... process results
100
});
101
102
logDb.withConnection(connection -> {
103
PreparedStatement stmt = connection.prepareStatement("INSERT INTO access_log (user_id, timestamp) VALUES (?, ?)");
104
stmt.setLong(1, userId);
105
stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
106
stmt.executeUpdate();
107
});
108
}
109
110
// Iterate over all databases
111
public void performHealthCheck() {
112
List<Database> databases = dbApi.getDatabases();
113
for (Database db : databases) {
114
try {
115
db.withConnection(connection -> {
116
PreparedStatement stmt = connection.prepareStatement("SELECT 1");
117
stmt.executeQuery();
118
});
119
System.out.println("Database " + db.getName() + " is healthy");
120
} catch (Exception e) {
121
System.err.println("Database " + db.getName() + " failed health check: " + e.getMessage());
122
}
123
}
124
}
125
}
126
```
127
128
### DefaultDBApi Implementation
129
130
Default implementation of the DBApi interface.
131
132
```scala { .api }
133
class DefaultDBApi(
134
configuration: Map[String, Config],
135
defaultConnectionPool: ConnectionPool = new HikariCPConnectionPool(Environment.simple()),
136
environment: Environment = Environment.simple(),
137
injector: Injector = NewInstanceInjector
138
) extends DBApi {
139
/** Try to initialize all the configured databases */
140
def initialize(logInitialization: Boolean): Unit
141
/** @deprecated Use initialize instead */
142
@deprecated("Use initialize instead, which does not try to connect to the database", "2.7.0")
143
def connect(logConnection: Boolean = false): Unit
144
}
145
```
146
147
**Usage Examples:**
148
149
```scala
150
import play.api.db._
151
import play.api.{Configuration, Environment}
152
import com.typesafe.config.ConfigFactory
153
154
// Create DBApi manually for testing
155
val config = Map(
156
"default" -> ConfigFactory.parseString("""
157
driver = "org.h2.Driver"
158
url = "jdbc:h2:mem:test"
159
"""),
160
"cache" -> ConfigFactory.parseString("""
161
driver = "org.h2.Driver"
162
url = "jdbc:h2:mem:cache"
163
""")
164
)
165
166
val dbApi = new DefaultDBApi(config)
167
dbApi.initialize(logInitialization = true)
168
169
try {
170
val defaultDb = dbApi.database("default")
171
val cacheDb = dbApi.database("cache")
172
// Use databases...
173
} finally {
174
dbApi.shutdown()
175
}
176
```
177
178
### Named Database Injection
179
180
Support for injecting specific databases by name using dependency injection.
181
182
```java { .api }
183
/** Qualifier annotation for dependency injection of named databases */
184
@Qualifier
185
@Retention(RetentionPolicy.RUNTIME)
186
public @interface NamedDatabase {
187
String value();
188
}
189
190
/** Implementation class for NamedDatabase annotation */
191
public class NamedDatabaseImpl implements NamedDatabase, Serializable {
192
public NamedDatabaseImpl(String value);
193
public String value();
194
}
195
```
196
197
**Usage Examples:**
198
199
```java
200
import play.db.*;
201
import javax.inject.Inject;
202
203
public class UserService {
204
private final Database userDb;
205
private final Database sessionDb;
206
207
@Inject
208
public UserService(
209
@NamedDatabase("users") Database userDb,
210
@NamedDatabase("sessions") Database sessionDb
211
) {
212
this.userDb = userDb;
213
this.sessionDb = sessionDb;
214
}
215
216
public void authenticateUser(String username, String password) {
217
// Use userDb for user lookup
218
Optional<User> user = userDb.withConnection(connection -> {
219
// User authentication logic
220
return findUser(username, password, connection);
221
});
222
223
if (user.isPresent()) {
224
// Use sessionDb for session management
225
sessionDb.withConnection(connection -> {
226
PreparedStatement stmt = connection.prepareStatement(
227
"INSERT INTO sessions (user_id, session_token, created_at) VALUES (?, ?, ?)"
228
);
229
stmt.setLong(1, user.get().getId());
230
stmt.setString(2, generateSessionToken());
231
stmt.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
232
stmt.executeUpdate();
233
});
234
}
235
}
236
}
237
```
238
239
### Package Object Type Alias
240
241
Type alias for compatibility between Scala and Java APIs.
242
243
```scala { .api }
244
package object db {
245
type NamedDatabase = play.db.NamedDatabase
246
}
247
```
248
249
## Configuration
250
251
Multiple databases are configured in `application.conf`:
252
253
```hocon
254
# Database configuration key (default: "db")
255
play.db.config = "db"
256
257
# Default database name (default: "default")
258
play.db.default = "default"
259
260
# Multiple database configurations
261
db {
262
default {
263
driver = "org.postgresql.Driver"
264
url = "jdbc:postgresql://localhost/myapp"
265
username = "dbuser"
266
password = "dbpass"
267
}
268
269
cache {
270
driver = "org.h2.Driver"
271
url = "jdbc:h2:mem:cache"
272
}
273
274
analytics {
275
driver = "org.postgresql.Driver"
276
url = "jdbc:postgresql://analytics-server/warehouse"
277
username = "analyst"
278
password = "secret"
279
pool = "hikaricp"
280
}
281
}
282
```
283
284
## Error Handling
285
286
- **IllegalArgumentException**: Thrown when requesting a database that doesn't exist
287
- **Configuration errors**: Thrown during initialization for invalid database configurations
288
- **Connection errors**: Thrown during database initialization if connections cannot be established
289
290
## Lifecycle Management
291
292
- **Initialization**: Call `initialize()` to set up all configured databases
293
- **Shutdown**: Call `shutdown()` to gracefully close all database connections and connection pools
294
- **Automatic lifecycle**: When using Play's dependency injection, lifecycle is managed automatically through `ApplicationLifecycle`