In a very large project where do we set up the database connection so that it is available across all the modules?
Suppose the requirement is like this:
LoginPage.html -> LoginServlet.java -> LoginService.java ==> Takes DB help to check the credentials.
Now, since the actual credentials are stored in DB, where do we set up the database so that the connection is available to all the modules?
In big projects, is database connection made as and when needed or database connections setup at the time when application is run and made available across all the modules.
If DB connections are made available to all the modules (which need DB connectivity), how is this achieved?
Thanks for your help and inputs.
Since you're not using an IoC approach (Spring), the alternative would be to have a static class (or a singleton) that has a reference to the DataSource. Whenever you need a Connection you only have to get it from that class:
public class JdbcUtils{
private static DataSource dataSource;
static{
dataSource = new DB2SimpleDataSource();
dataSource.setDatabaseName("DBNAME");
dataSource.setServerName("xxx.xxx.xxx.xxx");
dataSource.setPortNumber(447);
dataSource.setUser("USER");
dataSource.setPassword("PASS");
dataSource.setDriverType(4);
dataSource.setCurrentSchema("SCHEMA");
//OR even better get the DataSource through JNDI lookup if defined on server
}
public static Connection getConnection() throws SQLException{
return dataSource.getConnection()
}
}
Related
Looking at answers from high reputation users such as this it seems that it's appropriate to get a new DataSource object by querying the JNDI naming service on every single connection request. E.g. with code like the following (adapted from the linked answer for more brevity):
public class ConnectionManager{
public static Connection getConnection() throws NamingException {
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource dataSource = (DataSource)envContext.lookup("jdbc/test");
return dataSource.getConnection();
}
}
Is this really, the suggested / idiomatic way? In some of my own "ConnectionManager" utilty classes I used to keep a reference to the DataSource object as an instance variable. Nothing wrong came out of it except when the JBoss administrator disabled and enabled the connection pool from the admin console and then my code was getting errors like the following:
java.sql.SQLException: javax.resource.ResourceException: IJ000451: The connection manager is shutdown
So, is it an anti-pattern to keep around instances of DataSource objects in JDBC?
A DataSource object can be cached and is thread-safe, although JNDI ought to be well-enough optimized that getting the DS out of JNDI every request is negligible (the same instance will be handed back from JNDI).
If you're working in a Java EE environment for example, it's spec standard to be able to inject a DataSource at the class level, such as:
public class MyServlet extends HttpServlet {
#Resource
DataSource ds;
public void processRequest() {
try(Connection con = ds.getConnection()) {
// ...
}
}
}
Also, it's completely safe to share DataSource objects across multiple threads. On the other hand, sharing Connection objects across multiple threads is a big mistake, because those are NOT threadsafe per spec.
I have one master db. After login with master db I have some another db. Is it possible to connect at runtime to second db and also have instanace of first db also(master db) application using spring-jdbc or hibernate,
thanks in advance.
Yes, sure. You can create as many data sources as you need. Just define them in the Spring Context and autowire in you classes. This question might help you with defining components with the same type but different names.
UPD1: you can create a datasource at runtime just like that:
DataSource ds = new DataSource();
ds.setUsername("username");
ds.setPassword("password");
ds.setDriverClassName("com.mysql.jdbc.Driver"); // or another driver
ds.setUrl("jdbc:mysql://{hostname}:{port}/{dbName}?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false");
ds.setTestWhileIdle(true);
ds.setTestOnBorrow(true);
ds.setTestOnReturn(false);
ds.setValidationQuery("/* ping */ SELECT 1");
ds.setValidationQueryTimeout(1);
ds.setValidationInterval(30000);
ds.setTimeBetweenEvictionRunsMillis(30000);
ds.setMinIdle(1);
ds.setMaxWait(10000);
ds.setMaxIdle(10);
ds.setInitialSize(10);
ds.setMinEvictableIdleTimeMillis(30000);
I have configured MysqlDataSource in tomcat using this link.I have written junit test cases.when am i calling below connection from junit it throws following errors.
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
I have used following code
class DataConnection {
private static DataSource dataSource;
public DataConnection() {
try {
Context ctx = new InitialContext();
dataSource = (DataSource)ctx.lookup("java:comp/env/jdbc/test");
} catch (NamingException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
new DataConnection();
Connection con=dataSource.getConnection();
return con;
}
}
How to call tomcat from junit? How to achieve this?
The code you give gets the database connection from JNDI, e.g. when running in tomcat from the container. However, for Unit Tests (assuming that's what you use JUnit for) I'd rather suggest to use "dependency injection" - e.g. explicitly pass a database connection to the code under test or manually set it up before the test runs.
There's no need to rely on JNDI for executing your tests: That's not what you want to test, instead, you want to just verify that your actual code is running correctly.
You don't need any fancy library (e.g. spring) for dependency injection, just a slightly adjusted architecture. This will greatly enhance the testability of your application and lower the execution time of your tests.
(This is based on my assumptions of your situation based on the little bit of information that you give in your question)
Give TomcatJNDI a try. It is based on embedded Tomcat but initializes only Tomcat's JNDI environment without starting a server. So you can access all your resources as configured in Tomcat's configuration files in tests or from within any Java SE application. The API is simple. For instance to get a DataSource declared in context.xml:
TomcatJNDI tomcatJNDI = new TomcatJNDI();
tomcatJNDI.processContextXml(contextXmlFile);
tomcatJNDI.start();
Then you can lookup the DataSource as usual
DataSource ds = (DataSource) InitialContext.doLookup("java:comp/env/path/to/datasource")
More information about TomcatJNDI can be found here.
I am using spring & hibernate. my application has 3 modules. Each module has a specific database. So, Application deals with 3 databases. On server start up, if any one of the databases is down, then server is not started. My requirement is even if one of the databases is down, server should start as other module's databases are up, user can work on other two modules. Please suggest me how can i achieve this?
I am using spring 3.x and hibernate 3.x. Also i am using c3p0 connection pooling.
App server is Tomcat.
Thanks!
I would use the #Configuration annotation to make an object who's job it is to construct the beans and deal with the DB down scenario. When constructing the beans, test if the DB connections are up, if not, return a Dummy Version of your bean. This will get injected into the relevant objects. The job of this dummy bean is to really just throw an unavailable exception when called. If your app can deal with these unavailable exceptions for certain functions and show that to the user while continuing to function when the other datasources are used, you should be fine.
#Configuration
public class DataAccessConfiguration {
#Bean
public DataSource dataSource() {
try {
//create data source to your database
....
return realDataSource;
} catch (Exception) {
//create dummy data source
....
return dummyDataSource;
}
}
}
This was originally a comment:
Have you tried it? You wouldn't know whether a database is down until you connect to it, so unless c3p0 prevalidates all its connections, you wouldn't know that a particular database is down until you try to use it. By that time your application will have already started.
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.