My application was using Mongo DB earlier. Now, I'm shifting to PostgreSQL. For that, I've been migrating queries and all. But, I was being blocked by issue. In MongoDB connection, we've some MongoClientOptions used to improve the performance of the application. In some way, I want to set these options with JDBC for PostgreSQL also.
I've tried and searched the same functions in JDBC DriverManager class. But didn't find any.
MongoDB connection options used are added below,
How can I set these options for JDBC client for PostgreSQL?
MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
builder.threadsAllowedToBlockForConnectionMultiplier(1000);
builder.maxConnectionIdleTime(60* 1000 * 5);
builder.connectionsPerHost(100000);
MongoClientOptions options = builder.build();
mongoClient = new MongoClient(hostname, options);
In JDBC you pass a Properties object with some JDBC-standard properties ("user" and "password") and driver-specific properties, or pass the properties as part of the JDBC-url (with driver-specific properties and driver-specific syntax), or you configure things using a DataSource and its getters and setters.
For PostgreSQL JDBC refer to the section Connecting to the Database
For almost any serious usage of JDBC, you should not use DriverManager directly as it will create a new physical connection for each request. Instead use a javax.sql.DataSource implementation that provides connection pooling, either provided by your driver (those usually aren't very good though), a third-party library like HikariCP, or one built into your JavaEE application server.
Related
I am learning Java EE. My instructor told me to implement JNDI DataSource in my learning project. I have found some articles on the subject but I can't see clearly the steps to doing this.
My training project is a Spring MVC application. On the front end it has some Thymeleaf templates, and the data are taken from a PostgreSQL database.
What should be done to implement JNDI here? I don't even know why I need it. I was only told that this configuration should be considered obsolete and low-level, but I have no idea why.
Now the database is configured as follows:
a props file with the following content:
driver=org.postgresql.Driver
url=jdbc:postgresql://localhost/trainingproject
dbuser=postgres
dbpassword=Password
a .sql file which looks like this:
DROP TABLE IF EXISTS table1;
CREATE TABLE table1
(
row1 SERIAL PRIMARY KEY,
row2 CHARACTER VARYING(64)
);
a DataSource bean:
#Bean
public DataSource datasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getProperty(DRIVER));
dataSource.setUrl(environment.getProperty(URL));
dataSource.setUsername(environment.getProperty(USER));
dataSource.setPassword(environment.getProperty(PASSWORD));
}
PGSimpleDataSource implementation of DataSource is bundled with JDBC driver.
The JDBC driver for Postgres at https://jdbc.postgresql.org includes an implementation of DataSource: PGSimpleDataSource
PGSimpleDataSource ds = new PGSimpleDataSource() ;
ds.setServerName( "localhost" );
ds.setDatabaseName( "your_db_name_here" );
ds.setUser( "scott" );
ds.setPassword( "tiger" );
For more info:
The Javadoc for DataSource.
The Javadoc PGSimpleDataSource.
My Answer to the Question, Produce a DataSource object for Postgres JDBC, programmatically
The JDBC driver’s manual.
JNDI
Your question conflates two issues: DataSource and JNDI.
A DataSource is a simple object holding all the connection info needed to make a connection to a database. This includes a username, a password, the address of the database server, and any number of standard and proprietary feature settings. By proprietary, I mean Postgres-specific feature settings versus Microsoft SQL Server-specific versus Oracle-specific, etc. Look at the Javadoc for DataSource to see how simple it is, basically just a getConnection method. You can obtain a DataSource object with or without JNDI; the two are orthogonal issues.
JNDI is much more complex. JNDI is an interface for obtaining from a naming/directory server the configuration info needed by your app at runtime. Using this interface to such a server means you need not include deployment details in your codebase; you look up needed details on-the-fly at runtime.
Database connection info is but one of many kinds of info you might want to obtain from a JNDI server. You might also look up web services servers, logging services, and so on.
So rather than hard-coding your database connection info, you might want to “discover” the proper database connection info when launching your app. Your testing machines will use a bogus database server while your production deployment machines will use a different database server. These database servers may not be known to the programmer at compile time, or may not even exist yet. A look-up needs to be done, and JNDI is a standard way to do so without vendor lock-in.
How you configure database connection info to be delivered by a JNDI-compliant naming/directory server as a DataSource object to your app differs wildly depending on the particular server environment of your enterprise. Given your last code example, it looks like you are not actually accessing a JNDI server in your class, so JNDI is moot.
I'm using Spring Boot and JDBC for my database connection. I placed schema.sql at the classpath to initialize a schema and tables.
Because the schema doesn't exist yet while connecting to the datasource, I have to configure the datasource in application.properties like so:
spring.datasource.url=jdbc:mysql://localhost:3306/
schema.sql:
CREATE DATABASE IF NOT EXISTS <schema_name>
USE <schema.name>;
CREATE TABLE...
So I select the schema after creating it. This obviously doesn't persist for too long.
How do I configure this properly? Is there a way to select a default schema after the create script or maybe change the datasource url?
With JDBC you need to use Connection.setCatalog to switch between databases. You should not use USE <databasename> as the JDBC driver itself needs to be aware of which database it is operating on.
Based on your code from the schema.sql
USE <schema.name>;
This will not work for your java environment. The schema.sql will be executed and finished, which will not cater your requirement to set the default schema.
The General approach will be to use JDBC URL as;
jdbc:mysql://localhost:3306/DB_NAME
This will set the default db as DB_NAME.
Assumptions: I am assuming that you want to connect to single node DB without any loadbalancer or failover mechanism to be used. URL may change based on these features to be configured.
If you are not specifying the DB_NAME in the URL, it means their is no default schema.
You have 2 options to access the DB in that case.
1) Always use the Connection.setCatalog() method to specify the desired database in JDBC applications, rather than the USE database statement.
2) fully specify table names using the database name (that is, SELECT dbname.tablename.colname FROM dbname.tablename...) in your SQL. Opening a connection without specifying the database to use is generally only useful when building tools that work with multiple databases, such as GUI database managers.
For more details refer to the below mysql portal for reference.
https://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html
Question is basically identify the best practices on data access layer.
I want to choose in between using a data source or traditional driver manager to load the the connection on web applications. I know very clearly following advantages
Flexibility of configuration
In built connection pooling mechanism
But if I can sacrifice advantage of flexibility with configuration and have own connection pooling mechanism, Do I get any other benefit out of data source. In other way around what are limitations or issues I would face while having application managed jdbc driver connection than container managed.
I know the question is so stupid that I should be knowing the advantage of somebody takes care of handling connection than my application. But this is rare scenario where I can't use datasource in web application. I would be looking following things
How better I can design own connection pool my self?
Is there any thing else I should take care when I access connection through DriverManager API
Note that is is very possible to programmatically create a DataSource (backed by a connection pool) dynamically based on user input.
Using Apache Commons-dbcp:
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(DATABASE_DRIVER_CLASS);
ds.setUsername(DATABASE_USERNAME);
ds.setPassword(DATABASE_PASSWORD);
ds.setUrl(DATABASE_URL);
ds.setInitialSize(1);
ds.setMaxActive(50);
ds.setDefaultAutoCommit(false);
So I think the question is not really between a DataSource and no-DataSource, but rather between a container managed DataSource and an application managed DataSource.
Container managed DataSources are easier to manage by server-admin types. They can be tuned through the app server web UI, etcApplication managed DataSources do not have this advantage.
I am new to connection pooling i need suggestions in below scenario :
I have two projects which have hibernate connection pooling with spring.
Now i have a scenario where i have to create a new project which redirects the requests.
In the new project i have to authenticate the request by connecting to database, this will be the ONLY call to database in the whole project.
I was asked to go for hibernate which i feel is not required..as there is only one query to database , and is it not a good way to use JDBC connection for authenticating the request and connection pooling mechanisms available with jdbc to make sure connections are pooled ?
What is the best way ?
Use a connection pool library such as boneCP. It can be used both from Hibernate and directly;
your advisors may have a point after all: software projects have a tendency to acquire new features over time. If you start with Hibernate, there will be less code to rewrite once the pain threshold of manual JDBC is exceeded.
H2 has a range of compatibility modes for various other databases such as MS SQL Server, MySQL, Oracle, etc that support different SQL dialects. However, when setting up an embedded database in Spring I do not find any corresponding setting. Does this imply that I have to use "plain" SQL without any dialect specific features if I for example use Oracle in production and H2 during test? Have I overlooked something?
which version of H2 database? per the documentation, you can set compatible mode by SQL statement (http://www.h2database.com/html/features.html#compatibility)
SET MODE PostgreSQL
just add this statement into your first sql script file loaded by Spring jdbc embedded-database
According to the H2 doc, the Oracle compatibility mode is quite limited.
For instance, you can not use PL/SQL procedures.
If you use Spring's EmbeddedDatabase, you cannot set the compatibility mode as-is; you have to implement you own EmbeddedDatabaseConfigurer and specify the compatibility mode through the JDBC URL (see below).
But also, to use the compatibility mode with H2 and Spring, you just have to set the mode in your JDBC URL (so it is not Spring related) in a classic way, using a DataSource:
jdbc:h2:~/test;MODE=Oracle
And if you use Hibernate, you have to specify the Oracle dialect instead of the H2 one.
You have 2 options:
use spring to start the H2 database as follows (check setName() to see how to pass H2 specific URL parameters to spring builder):
Spring code generates the URL as follows:
String.format("jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1", databaseName)
So, in setName() you can all any H2 specific parameter in the URL.
private DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.H2)
.setName("testdb;DATABASE_TO_UPPER=false;MODE=Oracle")
.addScript("schema.sql")
.addScript("data.sql")
.build();
return db;
}
configure directly the DB URL, sth like:
org.h2.jdbcx.JdbcDataSource dataSource = new org.h2.jdbcx.JdbcDataSource();
dataSource.setURL("jdbc:h2:testdb;MODE=MySQL;DATABASE_TO_UPPER=false;INIT=runscript from 'src/test/resources/schema.sql'\;runscript from 'src/test/resources/data.sql'");
The main different is that (2) is executing scripts defined at INIT for every database connection creation and not once per DB creation! This causes various issues, like INSERTs failing due to duplicate keys etc..