How do I manually configure a DataSource in Java? - java

I'm trying to follow Sun's JDBC tutorial at http://java.sun.com/docs/books/tutorial/jdbc/basics/connecting.html
It gives the following example code:
DataSource ds = (DataSource) org.apache.derby.jdbc.ClientDataSource()
ds.setPort(1527);
ds.setHost("localhost");
ds.setUser("APP")
ds.setPassword("APP");
Connection con = ds.getConnection();
This code doesn't compile because the DataSource interface has none of these methods, except for the getConnection() method invoked last.
(Here's the javadoc: http://java.sun.com/javase/6/docs/api/javax/sql/DataSource.html)
What am I missing?
Edit:
I'm actually trying to connect to MySQL (com.mysql.jdbc) and I can't find the javadoc for that. I'll accept an answer that points me to either:
1) documentation for com.mysql.jdbc regarding a DataSource that I can understand, or
2) gives an example to follow for what the tutorial's code should be, for any database.

One thing you might want to look at is the Commons DBCP project. It provides a BasicDataSource that is configured fairly similarly to your example. To use that you need the database vendor's JDBC JAR in your classpath and you have to specify the vendor's driver class name and the database URL in the proper format.
Edit:
If you want to configure a BasicDataSource for MySQL, you would do something like this:
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("username");
dataSource.setPassword("password");
dataSource.setUrl("jdbc:mysql://<host>:<port>/<database>");
dataSource.setMaxActive(10);
dataSource.setMaxIdle(5);
dataSource.setInitialSize(5);
dataSource.setValidationQuery("SELECT 1");
Code that needs a DataSource can then use that.

DataSource is vendor-specific, for MySql you could use MysqlDataSource which is provided in the MySql Java connector jar:
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setDatabaseName("xyz");
dataSource.setUser("xyz");
dataSource.setPassword("xyz");
dataSource.setServerName("xyz.yourdomain.com");

Basically in JDBC most of these properties are not configurable in the API like that, rather they depend on implementation. The way JDBC handles this is by allowing the connection URL to be different per vendor.
So what you do is register the driver so that the JDBC system can know what to do with the URL:
DriverManager.registerDriver((Driver) Class.forName("com.mysql.jdbc.Driver").newInstance());
Then you form the URL:
String url = "jdbc:mysql://[host][,failoverhost...][:port]/[database][?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]"
And finally, use it to get a connection:
Connection c = DriverManager.getConnection(url);
In more sophisticated JDBC, you get involved with connection pools and the like, and application servers often have their own way of registering drivers in JNDI and you look up a DataSource from there, and call getConnection on it.
In terms of what properties MySQL supports, see here.
EDIT: One more thought, technically just having a line of code which does Class.forName("com.mysql.jdbc.Driver") should be enough, as the class should have its own static initializer which registers a version, but sometimes a JDBC driver doesn't, so if you aren't sure, there is little harm in registering a second one, it just creates a duplicate object in memeory.

use MYSQL as Example:
1) use database connection pools: for Example: Apache Commons DBCP , also, you need basicDataSource jar package in your classpath
#Bean
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/gene");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
2)use JDBC-based Driver it is usually used if you don't consider connection pool:
#Bean
public DataSource dataSource(){
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/gene");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}

I think the example is wrong - javax.sql.DataSource doesn't have these properties either. Your DataSource needs to be of the type org.apache.derby.jdbc.ClientDataSource, which should have those properties.

The javadoc for DataSource you refer to is of the wrong package. You should look at javax.sql.DataSource. As you can see this is an interface. The host and port name configuration depends on the implementation, i.e. the JDBC driver you are using.
I have not checked the Derby javadocs but I suppose the code should compile like this:
ClientDataSource ds = org.apache.derby.jdbc.ClientDataSource()
ds.setHost etc....

For postgres, the below works. I actually used it in integ tests. I guess there should be some more consideration for production usage.
PGSimpleDataSource ds = new PGSimpleDataSource() ;
ds.setServerName( "localhost" );
ds.setDatabaseName( "your_db_name_here" );
ds.setUser( "scott" );
ds.setPassword( "tiger" );
The class is bundled in the postgres jdbc driver.
The original stackoverflow post i followed: https://stackoverflow.com/a/45091982/3877642

Related

Simple-JNDI VS SimpleNamingContextBuilder with EmbeddedDatabaseBuilder and already existing Data Source

Does anyone knows to configure a EmbeddedDatabaseBuilder Datasource with Simple-JNDI?
I have a DataSource for testing purposes that I am building like this:
public DataSource dataSource() {
EmbeddedDatabase datasource = new EmbeddedDatabaseBuilder()
.setType(HSQL)
.setSeparator(";")
.addScript("classpath:/tables-definitions.sql")
.build();
return datasource;
}
And I want to bind this to a JNDI name with Simple-JNDI. Do you know how to do this?
Finally I found the answer how to use Simple-JNDI to bind to a jndi name a data source that you already have, in general for testing purposes.
Just an observation if you try to use SimpleNamingContextBuilder:
SimpleNamingContextBuilder is deprecated in spring 5.2 and above in favour of Simple-JNDI
Unfortunately I did not find a great source of documentation for Simple-JNDI which make things for more advanced stuff a bit cumbersome.
Also SimpleNamingContextBuilder does not work with JTA only with JPA - it does not cover all the naming needs for JTA
Now, how to bind a JNDI name with Simple-JNDI to a data source:
you need to set Context.INITIAL_CONTEXT_FACTORY to the factory class that you want to do the job for you, in my case I choose org.osjava.sj.memory.MemoryContextFactory - if you look into the location of this class in Simple-JNDI library, you will find more options there, depending of your needs
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.osjava.sj.memory.MemoryContextFactory");
Then you create a Hashtable and add all the properties you need to set as you set them through properties.
Hashtable env = new Hashtable();
env.put("org.osjava.sj.jndi.shared", "true");
Then you bind the DS to JNDI name as you would do it in old plain way:
create the initial context with the properties from the Hashtable
create the sub-context
then bind the data source to JNDI name/context:
InitialContext ic = new InitialContext(env);
ic.createSubcontext("java:/comp/env/jdbc");
ic.bind("java:/comp/env/jdbc/"+dataSourceJndiname, datasource);

HikariCP Address Specification and Documentation

So, after searching Google and Github for answers, I'm left confounded as to how most people know how to use HikariCP. I can't seem to find any straight up documentation on HikariCP.
My question is: how do I specify the host address without a JDBC URL? The main page of HikariCP on Github clearly says that JDBC URL specification is optional and instead to simply use HikariConfig#setDataSourceClassName(String). However, I'm confused then as to how I would specify my address and I can't seem to find the answer anywhere. Like with SQLite, where do I specify the path to where the database file should go?
This is the code I currently have:
final HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setPoolName("SQLite");
hikariConfig.setDataSourceClassName("org.sqlite.SQLiteDataSource");
HikariDataSource ds = new HikariDataSource(hikariConfig);
If I was to not use HikariCP I would simply specify the JDBC URL like such:
jdbc:sqlite:path/to/database.db. However, how do you do this without using a JDBC URL?
Thanks for any help.
When you use DataSource-style instead of URL-style configuration, all datasource properties translate to setters on the DataSource class. So, since you seem to be using the org.sqlite.SQLiteDataSource, the various setters on that class are what is relevant.
Here is an example of setting not only the URL of the DataSource, but also setting the Journal Mode and enabling full column name support.
final HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setPoolName("SQLite");
hikariConfig.setDataSourceClassName("org.sqlite.SQLiteDataSource");
hikariConfig.addDataSourceProperty("url", "jdbc:sqlite:C:/work/mydatabase.db");
hikariConfig.addDataSourceProperty("journalMode", "WAL");
hikariConfig.addDataSourceProperty("fullColumnNames", "true");
HikariDataSource ds = new HikariDataSource(hikariConfig);
This reason DataSource-style is preferable is two-fold:
The use of reflection ensures that any typo in a property name causes a failure. Whereas, properties with typos specified in the JDBC URL itself are typically ignored by drivers.
When there are a large number of properties specified, a JDBC URL connection string can get extremely long -- several hundred characters for some drivers -- which makes reading/understanding what properties are actually set extremely cumbersome.

For logging information, want the url used for connection of JNDI

I create a data source using standard below:
private DataSource ds;
Context envContext = (Context) initContext.lookup("java:/comp/env");
ds = (DataSource)envContext.lookup("jdbc/myDB");
I would want the connection url written to log file.
System.out.println(ds);
The above will not due. I thought about casting to BasicDataSource
(ds instanceof BasicDataSource);
to get information since BDS has getUrl() method. This goes against indirection, since not all connections will be BasicDataSource and should be avoided? How should one print the url used for a datasource, at least for debugging?
BasicDataSource and OracleDataSource (and probably other wrappers) are really the only ways to get URL information directly from the DataSource. But as gonzo described in the comments, you can get this information from your connection:
Connection conn = ds.getConnection();
String url = conn.getMetaData().getURL();

Working with DataSource, JNDI API in IntelliJ

I'm trying to understand establishing a database-connection with a DataSource Object and the JNDI API.
I'm working with Intellij UE and have a local Tomcat-8- and Postgres-Server running.
I proceed as mentioned in the Oracle Java Documentation:
Creating Instance of DataSource Class and Setting its Properties
org.postgresql.ds.PGSimpleDataSource dataSource = new org.postgresql.ds.PGSimpleDataSource();
dataSource.setServerName("localhost");
dataSource.setDatabaseName("db01");
dataSource.setUser("jwi");
dataSource.setPassword("password");
Registering DataSource Object with Naming Service That Uses JNDI API
Context ctx = null;
try {
ctx = new InitialContext();
ctx.bind("jdbc/localDB", dataSource);
} catch (NamingException e) {
e.printStackTrace();
}
The Oracle Documentation says:
With the properties set, the system administrator can register the BasicDataSource object with a JNDI (Java Naming and Directory Interface) naming service.
So my first Question is: What means to register a DataSource? Is my code obove already the registration of an DataSource Object to JNDI?
Using Deployed DataSource Object
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("jdbc/localDB");
dbCon = ds.getConnection();
...
In this code cutting IntelliJ always claims, that it can't resolve the method getConnection().
The Oracle Documentation says:
After a basic DataSource implementation is deployed by a system administrator, it is ready for a programmer to use.
So my second Question is: What exactly means deployed in this case? Creating a DataSource Instance and execute the registration with JDNI? Or does deployed mean the Tomcat context.xml and web.xml configuration (Tomcat 8 JNDI How-To)?
I'd really appreciate if anybody has a good step by step instruction for this issue, in fact that the Oracle Documentation isn't really clear about some points imho.
for the second question, deployed means that your datasource is declared in the context.xml in tomcat.
Here is an example of an oracle database (you have to change the driver for postgres) :
<Resource name="jdbc/myoracle" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#127.0.0.1:1521:mysid"
username="scott" password="tiger" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/>
After that, you can code the java part, for that you can watch this link http://www.javapractices.com/topic/TopicAction.do?Id=127
For a complete example, there's a good tutorial here http://alvinalexander.com/blog/post/java/how-configure-tomcat-dbcp-connection-pool-pooling-postgres.
Hope this help

How to get current Connection object in Spring JDBC

How can I get the current Connection object for an Oracle database? I'm using the JDBC module in Spring 3.0.5.
Obtain the Connection from the DataSource bean.
You can access the dataSource by using Spring dependency injection to inject it into your bean, or by accessing ApplicationContext statically:
DataSource ds = (DataSource)ApplicationContextProvider.getApplicationContext().getBean("dataSource");
Connection c = ds.getConnection();
Just an Info :
I am using Spring JDBC Template, which holds the current connection object for me, which can be received as follows.
Connection con;
con = getJdbcTemplate().getDataSource().getConnection();
Use DataSourceUtils.getConnection().
It returns connection associated with the current transaction, if any.
I'm not sure if this method was available when this question was originally posted, however, it seems the preferred way to do it in the latest version of Spring is with JdbcTemplate and PreparedStatementCreator. See https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html#query-org.springframework.jdbc.core.PreparedStatementCreator-org.springframework.jdbc.core.PreparedStatementSetter-org.springframework.jdbc.core.ResultSetExtractor- or any of the other query methods that take a PreparedStatementCreator as the first param:
jdbcTemplate.query(con -> {
// add required logic here
return con.prepareStatement("sql");
}, rs -> {
//process row
});
This has the advantage over the other provided answers (DataSourceUtils.getConnection() or jdbcTemplate.getDataSource().getConnection() as a new connection is not allocated, it uses the same connection management it would as calling any of the other jdbcTemplate querying methods. You also therefore do not need to worry about closing / releasing the connection, since spring will handle it.

Categories

Resources