Is it possible to configure multiple database connections in Dropwizard? - database

I am working on some code that leverages Dropwizard that will require that I need to connect to at least two different databases (I plan to use Hibernate as well). I was unable to find any examples/documentation that will allow me to configure two different database connections in the Database block of the .yml configuration file. Is this possible in Dropwizard? If not, what are the workarounds that people have used in the past. Thank you in advanced for your help!

You can configure multiple databases in dropwizard. In the config.yml you can have multiple database configuration like this.
database1:
driverClass: org.postgresql.Driver
user: user
password: pwd
url: jdbc:postgresql://localhost:5432/db1
validationQuery: select 1
minSize: 2
maxSize: 8
database2:
driverClass: org.postgresql.Driver
user: user
password: pwd
url: jdbc:postgresql://localhost:5432/db2
validationQuery: select 1
minSize: 2
maxSize: 8
And in the config class get both config details.
public class DBConfig extends Configuration {
private DatabaseConfiguration database1;
private DatabaseConfiguration database2;
public DatabaseConfiguration getDatabase1() {
return database1;
}
public DatabaseConfiguration getDatabase2() {
return database2;
}
}
And in your service configure which Dao to use which database.
#Override
public void run(MyConfiguration configuration,
Environment environment) throws ClassNotFoundException {
...
final DBIFactory factory = new DBIFactory();
// Note that the name parameter when creating the DBIs must be different
// Otherwise you get an IllegalArgumentException
final DBI jdbi1 = factory.build(
environment, configuration.getUserDatabase(), "db1");
final DBI jdbi2 = factory.build(
environment, configuration.getItemDatabase(), "db2");
final MyFirstDAO firstDAO = jdbi1.onDemand(MyFirstDAO.class);
final MySecondDAO secondDAO = jdbi2.onDemand(MySecondDAO.class);
...
}

Related

How to configure databases in springboot interchangeably

I need to enable code to interchangeably uses a different database by changing configuration. I have Oracle SQL and Azure SQL Server. By changing helm chart (or configuration), I would like to choose which database to use. Things I know are:
Datasource is configured in helm chart. I have a yaml file that declares driver, url, username and password for database.
env:
- name: datasource.project.driverClassName
value: 'oracle.jdbc.OracleDriver'
- name: datasource.project.url
value: 'url'
- name: datasource.project.username
value: 'username'
- name: datasource.project.password
value: 'password'
In my project, I create bean for database:
#Configuration
#EnableConfigurationProperties
public class ProjectDataSourceConfig {
public static final String DB_TX_MANAGER = "";
#Bean
#Primary
#ConfigurationProperties("datasource.project")
public DataSourceProperties projectDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
public DataSource projectDataSource() {
return projectDataSourceProperties().initializeDataSourceBuilder().type(ComboPooledDataSource.class).build();
}
#Bean
public NamedParameterJdbcTemplate projectJdbcTemplate() {
return new NamedParameterJdbcTemplate(projectDataSource());
}
#Bean(name = DB_TX_MANAGER)
public DataSourceTransactionManager projectDbtransactionManager() {
return new DataSourceTransactionManager(projectDataSource());
}
}
My goal is: to find a way to load either Oracle SQL OR Azure SQL Server by modifying configuration file. I am not sure if just changing driverClassName, url, username and password is sufficient enough.
I found this very easy. Since I don't use Hibernate, I can just simply change driver, url, username and password to Azure SQL's, then it works.

Easily switching between connection strings in .NET Core

I've got a code base that uses EF Core and Dapper to perform actions on a database.
I want to set up a new copy of the site to develop some features and I want this site to connect to a new isolated copy of the database (dbConnectionDEBUG).
At the moment, I use the following setup:
startup.cs
...
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("dbConnectionMain")));
services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
...
I have a ConnectionStrings class which is being populated correctly via the DI in startup:
public class ConnectionStrings
{
public string dbConnectionMain { get; set; }
public string dbConnectionDEBUG { get; set; }
public ConnectionStrings()
{
this.dbConnectionMain = "";
this.dbConnectionDEBUG = "";
}
}
Then, throughout my controllers/services I have access to ConnectionStrings and 99% of the time I'm doing the following to make DB calls:
using (var conn = new SqlConnection(_connectionStrings.dbConnectionMain))
{
conn.Open();
...
This would amount to a lot of code changes if I were to want to switch over to the 'DEBUG' db.
How do I easily switch between the connection strings in my code depending on what version of the system I'm working on.
If I could somehow do this dynamically that'd be great. The obvious determining factor would be the URL the site is operating on.
Alternatively, (as a single change) do I just manually change the connection string at the source (e.g keystore/appsettings). I'm not keen on this as it leaves room for human error.
Update (2)
Based on what #Nkosi mentioned I am pursuing this path:
Have one connection string 'Id' (i.e. dbConnection) used throughout
Differentiate the connection string value within this based on the environment the app is running/deployed in
I have another question:
If I have the following...
"MYAPPNAME": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:12345/;https://myapptestdomain.com/"
}
and:
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
IHostingEnvironment env = context.HostingEnvironment;
config.AddJsonFile($"appsettings.{env.EnvironmentName.ToLower()}.json", optional: true);
})
.UseStartup<Startup>();
...will this automatically pick up my site is in the Development mode based on the applicationUrl values OR will I have to manually add ASPNETCORE_ENVIRONMENT with a value Development on the server I deploy the app to?
Additional: My app is running in an Azure App Service.
Update (3) - Mission Complete
Just to finalise this question (in case anyone needs to know this), I have the following setup based on recommendations made by #Nkosi.
Connection String - I have one connection string Id/name dbConnection which is used in all appSettings (see below)
App Settings
I have a default appSettings.json with dbConnection that looks at the live database
I have an additional appSettings.Playground.json file with dbConnection that looks at my testing database
Azure - App Service - On my playground development slot I have added an App Setting for ASPNETCORE_ENVIRONMENT with the value 'Playground'
In my Program.cs file I have:
config.AddJsonFile($"appsettings.json", optional: true,reloadOnChange: true);
and
config.AddJsonFile($"appsettings.{env.EnvironmentName.ToLower()}.json", optional: true,reloadOnChange: true);
Just to note, I do also initialise a Vault on Azure which stores all my Keys and Secrets for the Azure based apps. Locally User Secrets is used.
ASP.NET Core reads the environment variable ASPNETCORE_ENVIRONMENT at app startup and stores the value in IHostingEnvironment.EnvironmentName.
Since the environment is being loaded, then it should be available from the hosting environment via the builder context
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) => {
string environment = context.HostingEnvironment.EnvironmentName; //get current environment
//load config based on environment.
config.AddJsonFile($"appsettings.{environment}.json", optional: true);
//...
})
//...
Reference Use multiple environments in ASP.NET Core
For simple apps and to keep the connection strings away from my repository I use preprocessor statements plus PATH/System Variables and for release I provide a connection string within the settings.json.
#define USE_FEATURE_X
using System;
namespace MyNamespace {
internal static class StaticConnectionStringFactory {
public static string GetConnectionString() {
#if DEBUG && !USE_FEATURE_X
var connectionString = Environment.GetEnvironmentVariable("CNNSTR_SQL_XYZ", EnvironmentVariableTarget.User);
#elif DEBUG && USE_FEATURE_X
var connectionString = Environment.GetEnvironmentVariable("CNNSTR_SQL_ABC", EnvironmentVariableTarget.User);
#else
var connectionString = Environment.GetEnvironmentVariable("SqlConnectionString", EnvironmentVariableTarget.Process);
#endif
return connectionString;
}
}
}
I think if you add 2 connection for debug and main then you will have face some difficulty because more member working in you team. may be some own wrongly use release mode for code development.
you can try this webconfig method:
public class ConnectionStrings
{
public string dbConnection { get; set; }
public ConnectionStrings()
{
bool Ismain = bool.Parse(System.Configuration.ConfigurationManager.AppSettings["HasLive"]);
if (Ismain)
{
dbConnection = "";// get Main connectionstring
}
else
{
dbConnection = "";// get Debug connectionstring
}
}
}
web.config:
<connectionStrings>
<add name="dbConnectionMain" connectionString="" providerName="System.Data.SqlClient" />
<add name="dbConnectionDEBUG" connectionString="" roviderName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
<add key="HasLive" value="false"/>
</appSettings>
</connectionStrings>

Change SQL Server Connection String Dynamically inside an ASP.Net Core application

I open one database at the start, then need to open another database based on user selecting two values. The database selection has to be at run-time and will change every time.
Have tried to access the Connection String using the Connection String class and have tried other options like Singleton which I do not understand. I am running this on a local Windows 10 system running SQL Server Express. Am coding using Asp.Net Core 2.1
> ASP.Net Core v2.1
Building multi tenant, multi year application
Every client will have one SQL DATABASE per year
I hope to have a table with the following structure
COMPANY_CODE VARCHAR(3),
COMPANY_YEAR INT,
COMPANY_DBNAME VARCHAR(5)
Sample Data
COMPANY_CODE: AAD
COMPANY_YEAR: 19
COMPANY_DB: AAD19
COMPANY_CODE: AAD
COMPANY_YEAR: 18
COMPANY_DB: AAD18
COMPANY_CODE: AAD
COMPANY_YEAR: 17
COMPANY_DB: AAD17
So, every company will multiple rows - one for each financial year.
The COMPANY_DB column will store the DB name to open for that session.
Once the user is authenticated, I want to change the connection string to point to the database in the COMPANY_DB column of the selected row and then let the logged in user perform transactions.
I am unable to figure out how to change the connection string that is embedded in startup.cs.
Any tips on how to achieve this will be most appreciated.
I figured out that you are using one DbContext class for each database. See here for more information: docs.
Remove AddDbContext from Startup, remove OnConfiguring from DbContext and pass options to the constructor.
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
}
Then, write service providing DbContext:
public interface IBlogContextProvider
{
BlogContext GetBlogContext(string connectionString);
}
public class BlogContextProvider : IBlogContextProvider
{
BlogContext GetBlogContext(string connectionString)
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connectionString);
return new BlogContext(optionsBuilder);
}
}
Add service in your Startup.cs:
services.AddScoped<IBlogContextProvider, BlogContextProvider>();
Now you can use DI:
public class HomeController : Controller
{
private IBlogContextProvider _provider;
public HomeController(IBlogContextProvider provider)
{
_provider = provider;
}
public ActionResult Index()
{
using (var context = _provider.GetBlogContext(<your connection string>))
{
//your code here
}
return View();
}
}
EDIT: Of course, you can write ContextProvider as generic.

Spring Boot REST: How to dynamically access the appropriate database schema specified in a client request?

I have one database with 3 schemas (OPS, TEST, TRAIN). All of these schemas have a completely identical table structure. Now lets say I have an endpoint /cars that accepts a query param for the schema/environment. When the user makes a GET request to this endpoint, I need the Spring Boot backend to be able to dynamically access either the OPS, TEST, or TRAIN schema based on the query param specified in the client request.
The idea is something like this where the environment is passed as a request param to the endpoint and then is somehow used in the code to set the schema/datasource that the repository will use.
#Autowired
private CarsRepository carsRepository;
#GetMapping("/cars")
public List<Car> getCars(#RequestParam String env) {
setSchema(env);
return carsRepository.findAll();
}
private setSchema(String env) {
// Do something here to set the schema that the CarsRepository
// will use when it runs the .findAll() method.
}
So, if a client made a GET request to the /cars endpoint with the env request param set to "OPS" then the response would be a list of all the cars in the OPS schema. If a client made the same request but with the env request param set to "TEST", then the response would be all the cars in the TEST schema.
An example of my datasource configuration is below. This one is for the OPS schema. The other schemas are done in the same fashion, but without the #Primary annotation above the beans.
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "opsEntityManagerFactory",
transactionManagerRef = "opsTransactionManager",
basePackages = { "com.example.repo" }
)
public class OpsDbConfig {
#Autowired
private Environment env;
#Primary
#Bean(name = "opsDataSource")
#ConfigurationProperties(prefix = "db-ops.datasource")
public DataSource dataSource() {
return DataSourceBuilder
.create()
.url(env.getProperty("db-ops.datasource.url"))
.driverClassName(env.getProperty("db-ops.database.driverClassName"))
.username(env.getProperty("db-ops.database.username"))
.password(env.getProperty("db-ops.database.password"))
.build();
}
#Primary
#Bean(name = "opsEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean opsEntityManagerFactory(
EntityManagerFactoryBuilder builder,
#Qualifier("opsDataSource") DataSource dataSource
) {
return builder
.dataSource(dataSource)
.packages("com.example.domain")
.persistenceUnit("ops")
.build();
}
#Primary
#Bean(name = "opsTransactionManager")
public PlatformTransactionManager opsTransactionManager(
#Qualifier("opsEntityManagerFactory") EntityManagerFactory opsEntityManagerFactory
) {
return new JpaTransactionManager(opsEntityManagerFactory);
}
}
Personally, I don't feel its right to pass environment as Request Param and toggle the repository based on the value passed.
Instead you can deploy multiple instance of the service pointing to different data source and have a gate keeper(router) to route to the respective service.
By this way clients will be exposed to one gateway service which in turn routes to respective service based on input to gate keeper.
You typically don't want TEST/ACPT instances running on the very same machines because it typically gets harder to [keep under] control the extent to which load on these environments will make the PROD environment slow down.
You also don't want the setup you envisage because it makes it nigh impossible to evolve the app and/or its database structure. (You're not going to switch db schema in PROD at the very same time you're doing this in DEV are you ? Not doing that simultaneous switch is wise, but it breaks your presupposition that "all three databases have exactly the same schema".

Using SQL Server 2008 Schema with JPA

I got a MS SQL Server (2008) database with two schemas, dbo as default for general purpose e.g. authentication and myapp for domain objects. I want to have JPA-Entitys in both Schemas. I use SpringBoot for configuration.
Entitys tables are created in the right schema as they should, e.g. myschema.job, but relationship tables, e.g. Job_Employee are created within the default schema dbo. How can I set in whicht schema automatically created tables are stored (without changing the default schema as this just shifts the problem)?
#Entity
#Table(schema="myschema")
public class Job {[...]
My application.yml looks like:
spring:
profiles: dev
datasource:
datasource1:
url: jdbc:sqlserver://localhost;databaseName=mydb;schema=myschema
username: SA
password: ###
datasource2:
url: jdbc:sqlserver://localhost;databaseName=mydb;schema=dbo
username: SA
password: ###
jpa:
show-sql: true
hibernate.ddl-auto : create-drop
properties:
hibernate.dialect: org.hibernate.dialect.SQLServer2012Dialect
hibernate.default_schema: dbo
And the datasources are Configured in
#Configuration
#EnableJpaRepositories
public class JPAConfiguration {
#Bean
#Primary
#ConfigurationProperties("spring.datasource.datasource1")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.datasource1")
public DataSource firstDataSource() {
return firstDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#ConfigurationProperties("spring.datasource.datasource2")
public DataSourceProperties secondDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#ConfigurationProperties("spring.datasource.datasource2")
public DataSource secondDataSource() {
return secondDataSourceProperties().initializeDataSourceBuilder().build();
}
}
Thanks!
The answer is: every Collection must be mapped to the right schema as well with #JoinTable annotation.
E.g. in our Case:
#JoinTable(schema="myschema")
#OneToMany(cascade=CascadeType.ALL)
#Column(nullable = false)
private List<Employee> employee;
This results in a table calles myschema.job_employee.

Resources