I have set up jdbc connection pooling in a java-ee environment by doing the following changes.
The context.xml
<Context>
<Resource name="jdbc/mysybase" auth="Container"
type="javax.sql.DataSource" driverClassName="com.sybase.jdbc3.jdbc.SybDriver"
url="jdbc:sybase:Tds:H2S33.studtrack.com:2025/student"
username="scott" password="tiger" maxActive="20" maxIdle="10"
maxWait="-1"/>
</Context>
In The web.xml file
<resource-ref>
<description>Sybase Datasource example</description>
<res-ref-name>jdbc/mysybase</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
And the jsp page
<%#page import="java.sql.*"%>
<%#page import="javax.naming.Context"%>
<%#page import="javax.naming.InitialContext"%>
<%#page import="java.sql.Connection"%>
<%#page import="java.sql.SQLException"%>
<%#page import="java.sql.ResultSet"%>
<%#page import="javax.sql.DataSource"%>
<html>
<head>
<title>Obtaining a Connection</title>
</head>
<body>
<%
Connection conn = null;
ResultSet result = null;
Statement stmt = null;
try {
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/mysybase");
conn = ds.getConnection();
if (conn != null)
{
String message = "Got Connection " + conn.toString() + ", ";
out.write(message);
}
else
{
out.write("hello no conn obtained");
}
stmt = conn.createStatement();
result = stmt.executeQuery("SELECT * FROM Student");
while(result.next())
{
out.write(result.getString("name"));
}
}
catch (SQLException e) {
out.write("Error occurred " + e);
}
%>
</body>
</html>
Now i want the jdbc pooling to be available in normal java classes as well.
Do i need to make any changes if i want the pooling to be available in java classes.
Can i get a connection object in a java class just as i got the connection in the jsp as shown above.
Connection conn = null;
ResultSet result = null;
Statement stmt = null;
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/mysybase");
conn = ds.getConnection();
1.) You can set a contextListener to initialize connection only once and get logical conn from the pool (gues you use tomcat's DBCP).
2.) Yes, once you start a connection (driver sets a socket and the pool gets initialized) from context data, you can get a connection (from the pool) properly invoking that from any java class.
3.) Try not to put pure Java code in JSPs. Just a rule of the road: is treated as a poor decision.
Yes, you used JNDI(Java Naming and Directory Interface) standard for preparing connection, so you can same code in java classes for access to connection.(of course you have to initial Context instance befor using it for example have to set connection factory for it ).
I see your code and find these note, for better application you have to observance it:
You using jdbc in presentation layer, better approch is:"desing Data Access layer".
You can using a famous connection pooling, such as "C3P0" and "Apache Tomcat 7 Connection Pool", these connection pools have more option for enterprise application.(of course you have to test your current connection pool with these suggestion)
You can use a ORM for data access layer, this is object oriented design.
Related
I am using jdbc connection pooling and i am getting the connection more than 100 place in the web application. how can i write the common code in single class and call, where required.
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/UserDB");
Connection con = ds.getConnection();
I am trying to connect a Java application to a SQL database that I set up on my local computer. There is no server so all of the answers im finding when trying to research it are not working or applicable. The error I get when I run this is:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
Caused by: java.net.ConnectException: Connection refused: connect
I have verified the username and password for SQL and verified that the account has full admin rights. Any ideas? Im at a loss...
package database_console;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnect {
public static void main(String[] args) {
try{
String host= "jdbc:mysql://[myIPaddress]/MTGDatabase";
String uName = "Java";
String uPass = "pass";
Connection con = DriverManager.getConnection(host , uName, uPass );
}
catch(Exception e){
e.printStackTrace();
}
}
}
Replace the [myIPaddress] with the either "127.0.0.1:3306" or "localhost:3306".
'127.0.0.1' and 'localhost' are the same thing referring to your own local machine.
3306 is the port on which MqSQL is listening for new connections.
String host = "jdbc:mysql://localhost:3306/MTGDatabase";
or
String host = "jdbc:mysql://127.0.0.1:3306/MTGDatabase";
This should solve your current problem :)
But on a different node :
It is quite an old technique to obtain database connections via DriverManager. A more better way is to use DataSource, either by looking one up that your server container already configured for you:
Context context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("java:comp/env/jdbc/MTGDatabase");
or instantiating and configuring one from your database driver directly:
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUser("Java");
dataSource.setPassword("pass");
dataSource.setServerName("localhost");
and then obtain connections from it, same as above:
Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM MYTABLE");
...
rs.close();
stmt.close();
conn.close();
You need put the port String host= "jdbc:mysql://[myIPaddress]:[port]/MTGDatabase"; and create a Statement to execute querys Statement stmt=con.createStatement();
I have created Datasource and try to get connection object using the below code,
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, "t3://localhost:7001");
java.sql.Connection vendorConn = null;
try {
ctx = new InitialContext(ht);
javax.sql.DataSource ds
= (javax.sql.DataSource) ctx.lookup("jdbc/myDataSource");
conn = ds.getConnection();
} catch (SQLException e) {
LOGGER.error(e.getMessage());
}
Below I have mentioned connection object and callable object,
weblogic.jdbc.rmi.SerialConnection_weblogic_jdbc_rmi_internal_ConnectionImpl_weblogic_jdbc_wrapper_JTAConnection_weblogic_jdbc_wrapper_XAConnection_oracle_jdbc_driver_LogicalConnection_12130_WLStub#d4
cstmt = (weblogic.jdbc.rmi.SerialCallableStatement_weblogic_jdbc_rmi_internal_CallableStatementStub_weblogic_jdbc_rmi_internal_CallableStatementImpl_weblogic_jdbc_wrapper_CallableStatement_oracle_jdbc_driver_OracleCallableStatementWrapper_12130_WLStub) weblogic.jdbc.rmi.SerialCallableStatement_weblogic_jdbc_rmi_internal_CallableStatementStub_weblogic_jdbc_rmi_internal_CallableStatementImpl_weblogic_jdbc_wrapper_CallableStatement_oracle_jdbc_driver_OracleCallableStatementWrapper_12130_WLStub#145
I am getting the below exception when i called a store procedure using callable
java.sql.SQLException: weblogic.rmi.extensions.RemoteRuntimeException:
Unexpected Exception
at weblogic.jdbc.rmi.SerialStatement.close(SerialStatement.java:126)
at weblogic.jdbc.rmi.SerialStatement.close(SerialStatement.java:110)
at weblogic.ejb.container.internal.MDListener.execute(MDListener.java:451)
at weblogic.ejb.container.internal.MDListener.transactionalOnMessage(MDListener.java:375)
at weblogic.ejb.container.internal.MDListener.onMessage(MDListener.java:310)
at weblogic.jms.client.JMSSession.onMessage(JMSSession.java:4855)
at weblogic.jms.client.JMSSession.execute(JMSSession.java:4529)
at weblogic.jms.client.JMSSession.executeMessage(JMSSession.java:3976)
at weblogic.jms.client.JMSSession.access$000(JMSSession.java:120)
at weblogic.jms.client.JMSSession$UseForRunnable.run(JMSSession.java:5375)
at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:548)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)
java.sql.SQLException: prepareStatement, Exception = Unexpected Exception
at weblogic.jdbc.rmi.RMIWrapperImpl.invocationExceptionHandler(RMIWrapperImpl.java:102)
at weblogic.jdbc.rmi.RMIStubWrapperImpl.invocationExceptionHandler(RMIStubWrapperImpl.java:34)
at weblogic.jdbc.rmi.SerialConnection.prepareStatement(SerialConnection.java:236)
at weblogic.ejb.container.internal.MDListener.execute(MDListener.java:451)
Please suggest is this the right way to use Datasource connection where all my sql statements are working but procedure is not getting called and also I need Is it required to typecast the SerialConnection to sql.Connection.
CallableStatement cst = null;
try {
cst = conn
.prepareCall("{call myProc(?,?,?,?,?,?,?,?)}");
final String typeTableName = "studentdetails";
cst.setInt(1, student.getEmpid());
cst.setInt(2, student.getOrgid());
cst.setInt(3, student.getYearid());
cst.setString(4, student.getClassType());
cst.setInt(5, student.getStudentid());
cst.registerOutParameter(6, Types.ARRAY, typeTableName);
cst.registerOutParameter(7, java.sql.Types.VARCHAR);
cst.registerOutParameter(8, java.sql.Types.VARCHAR);
long startTime=System.currentTimeMillis();
cst.execute();
String dat=cst.getString(7);
//Array arr = cst.getArray(6);
long endTime=System.currentTimeMillis();
if (null != cst.getObject(6)) {
data = (Object[]) ((Array) cst.getObject(6)).getArray();
}
If I use datasource, I am getting cst.getObject(6) as null, but if use normal jdbc connection it is working fine by providing the object.
If you are using Weblogic you must add the following element to your weblogic.xml
<resource-description>
<res-ref-name>datasource_ref</res-ref-name>
<jndi-name>jdbc/myDataSource</jndi-name>
</resource-description>
Then you must reference it from your deployment descriptor web.xml by adding following element
<resource-ref>
<res-ref-name>datasource_ref</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Then you can reference your Data Src from your Java code like follows,
Context cntxt= (Context)new InitialContext().lookup("java:comp/env");
DataSource ds= (DataSource)cntxt.lookup("datasource_ref");
Or by using resource injection like follows,
#ApplicationScoped
public class DBHandler{
#Resource(name="datasource_ref")
private javax.sql.DataSource myDB;
public Connection getConnection(){
return myDB.getConnection();
}
}
And you can use it on demand anywhere using CDI
DBHandler handler = CDI.current().select(DBHandler.class).get();
Or by field injection
#Inject
javax.enterprise.inject.Instance<DBHandler> instance;
....
void persist(){
DBHandler handler=instance.get();
Connection con= handler.getConnection();
}
I have an application that i use for buiding reports, now I need to move this application to Web environment.
For that I am using Tomcat 8.0.15 and an Oracle Database 11g Enterprise Edition.
In my TOMCAT_HOME\conf\server.xml i have the following code:
<Resource auth="Container"
driverClassName="oracle.jdbc.OracleDriver"
maxIdle="10"
maxTotal="20"
maxWaitMillis="-1"
name="jdbc/reportDataSource"
username="some_username"
password="some_pass"
type="javax.sql.DataSource"
url="jdbc:oracle:thin:#(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = some.host)(PORT = some.port)))(CONNECT_DATA =(SID = SOME_SID)(SERVICE_NAME = SOME_SERVICE)))"/>
Therefore in my PROJECT_HOME\WebContent\WEB-INF\web.xml I have the following:
<resource-ref>
<description>Oracle Datasource definition</description>
<res-ref-name>jdbc/reportDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Finally in my code I have a Java class with the following:
private void init() throws NamingException, SQLException {
try {
InitialContext initialContext = new InitialContext(); // JNDI initial context
Context eventContext = (Context) initialContext.lookup("java:comp/env/jdbc/reportDataSource"); // Event context
dataSource = (DataSource) eventContext.lookup("jdbc/reportDataSource"); // JNDI lookup
databaseConnection = dataSource.getConnection(); // database connection through data source
} catch (SQLException se) {
throw new SQLException("Connection object was not created. Rejected by host or not found.");
} catch (NamingException ne) {
throw new NamingException(ne.getMessage());
}
}
Finally in my project root I have have the following test setup:
#Before
public void setUp() throws Exception {
dbConnectorManager = new DatabaseConnectorManager();
assertNotNull(dbConnectorManager);
}
When I call the DatabaseConnectorManager() it calls the init() method shown in this question. However when I execute my test I got the following error related with line:
entContext eventContext = (Context) initialContext.lookup("java:comp/env/jdbc/reportDataSource"); // Event context
Hence, it is not possible to setup JNDI due the following error:
javax.naming.NamingException: 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
Can you please advise if I can create these JUnit tests for testing the connectivity, or if I can only test through a servlet?
Is there anything wrong with my configuration?
Update
I made the desiganted changes but now I get the following error:
javax.naming.NamingException: Name [jdbc/reportDataSource] is not bound in this Context. Unable to find [jdbc].
My data source now looks like the following:
InitialContext initialContext = new InitialContext(); // JNDI initial context
Context eventContext = (Context) initialContext.lookup("java:comp/env"); // Event context
dataSource = (DataSource) eventContext.lookup("jdbc/reportDataSource"); // JNDI lookup
databaseConnection = dataSource.getConnection(); // database connection through data source
'not sure this is the error, but you probably have a typo here:
Context eventContext =
(Context) initialContext.lookup("java:comp/env/jdbc/reportDataSource"); // Event context
// ^^^^^^^^^^^^^^^^^^^^^^
dataSource = (DataSource) eventContext.lookup("jdbc/reportDataSource"); // JNDI lookup
// ^^^^^^^^^^^^^^^^^^^^^^
Either you want to do a direct lookup:
dataSource =
(DataSource) initialContext.lookup("java:comp/env/jdbc/reportDataSource");
Or you want to get the context first, but in that case, you only requests java:comp/env:
Context eventContext =
(Context) initialContext.lookup("java:comp/env");
dataSource = (DataSource) eventContext.lookup("jdbc/reportDataSource");
In Server.xml, provide a name to your resource and do the lookup based on that name. Another point is, you can add a resource as a new context.xml under META-INF folder under webapps. This is done if you don't want to change your server.xml
<Resource name="tomcat/JDBCdatasource" auth="Container" ... />
Context ctx;
ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:/comp/env");
// Look up a data source
javax.sql.DataSource ds
= (javax.sql.DataSource) envContext.lookup ("tomcat/JDBCdatasource");
I am learning Spring MVC. I am trying to use #Resource to inject DataSource. It is like this:
web.xml of Tomcat:
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
context.xml:
Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="sa" password="" driverClassName="org.h2.Driver"
url="jdbc:h2:tcp://localhost/~/test"/>
The controller code (using Spring MVC framework):
#Controller
public class SimpleControllerAnnotation {
//#Resource(name="dataSource")
#Resource(name="jdbc/TestDB")
private DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
//#Resource(name="dataSource")
#Resource(name="jdbc/TestDB")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
#RequestMapping("/testDataSource")
public ModelAndView testDataSource() {
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
String name = null;
String ID = null;
try {
con = dataSource.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select ID, name from STUDENT");
while(rs.next()){
name = rs.getString("name");
ID = rs.getString("ID");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
ModelAndView mw = new ModelAndView("TestDataSourceForm");
mw.addObject("DataSourceValue",dataSource);
mw.addObject("Name",name);
mw.addObject("ID",ID);
return mw;
}
In this code, I am using #Resource to inject the DataSource, which I intend to "get" from Tomcat, which I set up in Tomcat (the web.xml and context.xml shared above).
When I run this program, I get the following exception:
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleControllerAnnotation': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'jdbc/TestDB' is defined
The jdbc/TestDB is the DataSource which I set up in Tomcat.
I have following queries:
1) Is it possible to have DataSource which we create in Tomcat to be injected this way? Or we have to use JNDI lookup. In one of the posts that I read on internet, it was said that JNDI lookup is sort of outdated and these days Dependency injection is preferred way.
2) In general, is it best practice to set-up the DataSources in App server/Web Container or to manage in the application itself. From what I read over the posts, it is preferred let App server/Container to manage this.
Any help to past this error really appreciated.
Apache Tomcat processes #Resource annotations only on classes that it itself loads (such as Filters, Servlets and Listeners).
In your case your controller class is loaded by Spring Framework and Spring is responsible for processing the #Resource annotation. Read the Spring documentation (Reference guide).
According to Spring Reference Guide [1], the value in #Resource annotation is the name of a Spring bean.
It says that the name can be used for JDNI lookup if you configure a SimpleJndiBeanFactory, but recommends against it and advices to configure referenced beans explicitly. -> [2]
[1] http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-resource-annotation
[2] http://docs.spring.io/spring/docs/current/spring-framework-reference/html/xsd-config.html#xsd-config-body-schemas-jee