I'm trying to connect a JEE app to a MySQL database. There is a lot of documentations and similar questions on this topic, but none of the solutions i've found works so far (Nonetheless, I may have miss one in particular so feel free to propose).
The server name is db and the database name is joinmyparty
Here is my java code to connect :
public class MySqlConnection {
private static Connection conn;
public static Connection getConn() {
try {
Context initContext = new InitialContext() ;
Context envContext = (Context)initContext.lookup("java:/comp/env") ;
DataSource ds = (DataSource) envContext.lookup("jdbc/joinmyparty") ;
conn = ds.getConnection();
} catch (NamingException e) {
System.out.println("Cannot get connection: " + e);
} catch (SQLException e) {
System.out.println("Cannot get connection: " + e);
}
return conn;
}
Every time I call a DAO, I use this method getConn() to open a connection and i close it in the finally block.
I wrote this into my /tomcat/conf/context.xml file :
<?xml version="1.0" encoding="UTF-8"?>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<Resource url="jdbc:mysql://db:3306/joinmyparty"
driverClassName="com.mysql.jdbc.Driver" password="mypassword"
username="myusername" maxWait="10000" maxIdle="30"
maxActive="100" type="javax.sql.DataSource" auth="Container"
name="jdbc/joinmyparty" validationQuery="select 1" testOnBorrow="true"/>
</Context>
I've tried to put the mysql-connector .jar into the /tomcat/lib or into the /WEB-INF/lib and into the build-path. I've also tried multiple versions of connectors (but only one at a time), especialy to get the one with same level as MySQL database.
When I call a servlet which requires to connect the database, I've a blank page with a POST() method and an error 5OO with a GET() method.
Here is the log error (I tried to translate it my best since i'm not english native) :
description : this server has encountered an internal error which prevents it from fulfilling your request
exception
java.lang.NullPointerException
com.picco.user.dao.UserDao.findByEmail(UserDao.java:40)
com.picco.user.servlet.Index.doGet(Index.java:56)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
And here the part of the code concerned (but as I said, all codes using DAO have the same problem).
try {
UserDao udao = new UserDao();
User u = udao.findByEmail(myCookieVal);
SongDao sdao = new SongDao();
ArrayList<Song> list = sdao.getAllSongs(u.getId());
Random rd = new Random();
int count = udao.count();
request.setAttribute("currentSong", list.get(rd.nextInt(list.size())));
request.setAttribute("songList", list);
request.setAttribute("partyCount", count);
this.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
} catch(SQLException e) {
e.printStackTrace();
} finally {
HsqlConnection.closeInstance();
}
Dont hesitate to ask me for details if I did not describe enought the problem.
Maybe the problem is that you try to fetch the resource User before having instantiated the connection that is set to null.
The MySQL JDBC JAR belongs in the Tomcat /lib folder. You want the Tomcat class loader to find it first.
Shouldn't your DAO get a connection? I'd add it to the constructor.
Related
I have a Wildfly Java application running with a MariaDB database. Initially the connection works fine, but after 20 connections (the default) the next time it tries to connect the server hangs and after around one minute it throws the following exception:
javax.resource.ResourceException: IJ000453: Unable to get managed connection for java:jboss/datasources/IndustryDS
This is how I connect and close the datasource:
private InitialContext context = null;
private DataSource ds = null;
private Connection conn = null;
try {
context = new InitialContext();
ds = (DataSource)context.lookup(pool);
conn = ds.getConnection(); // <--- here is where it hangs
// use the connection
if (conn != null)
conn.close();
if (context != null)
context.close();
}
catch (NamingException e) {
logger.error(e.getMessage());
throw new DAOException(e.getMessage());
}
catch (SQLException e) {
logger.error(e.getMessage());
throw new DAOException(e.getMessage()); // <--- this error is thrown
}
The datasource configuration in standalone.xml
<datasource jta="true" jndi-name="java:jboss/datasources/IndustryDS"
pool-name="IndustryDS" enabled="true" use-java-context="true">
<connection-url>jdbc:mariadb://localhost:3306/industry</connection-url>
<driver>mariadb</driver>
<security>
<user-name>user</user-name>
<password>xxxxxx/password>
</security>
</datasource>
By default, MariaDB supports 150 connections so the database shouldn't be the problem. The default maximum pool size in Wildfly is 20 and I'm the only user in the system. Every time I initiate a function in my application I request two connections and then disconnect.
Why the datasource connections are not available even when I close them?
Here's what worked for me.
Enable cached connection manager in debug mode
<cached-connection-manager debug="true" error="true"/>
Look for this text in your log file - "Closing a connection for you. Please close them yourself". This will help help you find the leak in your code.
In my case, jdbcTemplate.getConnection().createClob() was causing the pool to exhaust.
try {
Connection conn = jdbcTemplate.getConnection()
....
conn.createClob();
...
} catch() {
...
} finally {
conn.close()
}
So properly closing the connection as shown above worked for us.
Hope this saves a lot of time for someone.
One problem with your code is that the context and connection may not be closed if there is an exception.
The old way to solve this was to close the resources in in a finally block. The modern way is to use try with resources. For example:
try (InitialContext context = new InitialContext();
Connection conn = ((DataSource) context.lookup(pool)).getConnection()) {
// use the connection
} catch (NamingException e) {
logger.error(e.getMessage());
throw new DAOException(e.getMessage());
} catch (SQLException e) {
logger.error(e.getMessage());
throw new DAOException(e.getMessage());
}
The try with resources starts with resource declarations where the resources are declared and initialized. Then there is a body where the resources are used. Finally you have (optional) catch and finally blocks.
The secret sauce is that the try with resources construct will automatically close each of the (non-null) resources, in reverse order that they were opened. Exceptions thrown by the close calls will be dealt with appropriately. And so on.
(You can achieve (more or less) the same thing in the old way with finally blocks, but it is complicated.)
I've done this a very different way using JPA and never had an issue. My code looks something like:
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
public class MyClass {
#PersistenceContext
private EntityManager entityManager;
public SomeObject getSomeObject() {
// as an example query
Query query = entityManager.createQuery("select ...")
}
}
There is some additional configuration needed in META-INF/persistence.xml that looks like:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="somethingPU" transaction-type="JTA">
<jta-data-source>jdbc/yourJNDIName</jta-data-source>
</persistence-unit>
</persistence>
In this way you're not ever dealing with connection management - the container (Wildfly in your case) takes care of it for you.
I am using Tomcat version 8 and MySQL connector ver 6. Here is my context.xml:
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<Resource auth="Container"
driverClassName="com.mysql.cj.jdbc.Driver"
maxActive="20"
maxIdle="10"
maxWait="-1"
name="jdbc/MyConn"
username="root"
password="mypassword"
type="javax.sql.DataSource"
url="jdbc:mysql://localhost:3306/training_db"
/>
This is the class I use for DB connection.
public class DBConnection {
public static Connection getConnection() throws Exception{
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/MyConn");
Connection conn = ds.getConnection();
System.out.println("dbConLookp():: Data Source Connection is called."+ds.getLogWriter());
return conn;
}
}
This is what I have for connecting to database and do insertions.
try{
DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
Connection con = DBConnection.getConnection();
PreparedStatement st = con.prepareStatement("INSERT INTO EMPLOYEE (ID,FIRSTNAME,LASTNAME,MIDDLENAME,PHONENUMBER,EMAILID,ADDRESS,USERPASS) VALUES (?,?,?,?,?,?,?)");
st.setInt(1, Integer.parseInt(request.getParameter("id")));
st.setString(2, firstName);
st.setString(3, lastName);
st.setString(4, middleName);
st.setString(5, phoneNumber);
st.setString(6, emailId);
st.setString(7, address);
st.setString(8, password);
boolean rs = st.execute();
if (!rs) {
System.out.println("Record "+request.getParameter("id")+" is inserted successfully.");
} else {
System.out.println("Record is insertion is failed.");
}
st.close();
con.close();
}
catch(Exception e){
System.out.println("Exception caught:" + e);
}
On Register page, when I click register, I get java.sql.SQLException: Cannot create PoolableConnectionFactory (CLIENT_PLUGIN_AUTH is required) exception. I tried changing localhost to 127.0.0.1 but it didn't work. I also checked MySQL permissions and they look fine. I tried creating a different user but it didn't work as well. I tried moving creating another context.xml in my WEB-INF folder but no luck. I don't know what else can I do. Any help is appreciated.
In case anyone experiences the same issue, I remembered that I copied MySQL Connector JAR's into Tomcat's lib folder as suggested by a StackOverflow answer from a related question. Delete those JAR's and you'll be good to go.
I also needed to downgrade my connector version to v5.1.39. Try different connector versions if you still experiencing problems.
I have made a web application using tomcat that is connecting to the database and made some transactions on it, but my database oracle admin is complaining of so many connection from it and tells me that it is always cause the database to hang up due to many connection . so my question is what the best context.xml file to use and what modification should i do to mine?
my context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/applicationName">
<Resource driverClassName="oracle.jdbc.OracleDriver"
maxActive="100" maxIdle="-1" maxWait="30000" name="name" password="password"
type="javax.sql.DataSource" url="url"
username="username" />
</Context>
my Dao Class
public Dao(){
}
Context initContext;
Context envContext;
DataSource ds;
Connection conn;
public Connection getConnection() throws Exception {
initContext = new InitialContext();
envContext = (Context) initContext.lookup("java:/comp/env");
ds = (DataSource) envContext.lookup("name");
conn = ds.getConnection();
if(conn != null){
return conn;
}
return null;
}
Verify that you are closing the connection properly in the code.
Also, you should try
finally {
if(connection!= null) {
connection.close();
connection = null;
}
}
This is the first time I am using SQL Server, previously I was working on MySQL and I was creating db connection pool in tomcat successfully. I am trying to use same code to create a connection pool for sql server. Please guide me where I am going wrong.
I am trying login as Windows Authentication, I have copied sqljdbc_auth.dll in tomcat bin directory.
Following is the code I wrote in my context.xml file under META-INF:
Context antiJARLocking="true" path="">
<Resource
auth="Container"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
logAbandoned="true"
maxActive="100"
maxIdle="30"
maxWait="1000"
name="jdbc/mydb"
removeAbandoned="true"
removeAbandonedTimeout="60"
type="javax.sql.DataSource"
url="jdbc:sqlserver://localhost;integratedSecurity=true;" />
</Context>
And below is the java class which is providing connections:
public class ConnectionPool {
private static ConnectionPool pool=null;
private static DataSource dataSource = null;
public synchronized static ConnectionPool getInstance(){
if (pool == null){
pool = new ConnectionPool();
}
return pool;
}
private ConnectionPool(){
try{
InitialContext ic = new InitialContext();
dataSource = (DataSource) ic.lookup("java:/comp/env/jdbc/mydb");
}
catch(Exception e){
System.out.println(e);
}
}
public Connection getConnection(){
try{
return dataSource.getConnection();
}
catch (SQLException sqle){
System.err.println(sqle);
return null;
}
}
public void freeConnection(Connection c){
try{
c.close();
}
catch (SQLException sqle){
System.err.println(sqle);
}
}
}
When I tried calling getConnection() then I got following exception:
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
Exception in thread "main" java.lang.NullPointerException
at ConnectionPool.getConnection(ConnectionPool.java:39)
Can you please provide the steps on how to use sqlite in tomcat 6? I am using Xerial sqlite jdbc driver. In my application, I have got multiple sqlite databases (.db files) and would need to connect to a different sqlite database depending on what user logs in ? Where can I put all the .db files - with in the webapp root's directory or any where on the system or with in WEB-INF?
Thanks,
Deep
I just went through configuring sqlite3 with Tomcat 7. Everything is working now, so thought I'd share my setup.
- Download the JDBC driver (org.sqlite.JDBC) that lives in sqlite-jdbc-3.7.2.jar (or whatever the latest version is). https://bitbucket.org/xerial/sqlite-jdbc/downloads and copy it to yourTomcat/lib
- You can copy the sqlite db anywhere you want to. For my setup, I created a 'dbs' directory under my tomcat install, and put it there.
Now set up your app. If you don't have a META-INF/context.xml file, then create one. This is a minimal file:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/yourdb"
auth="Container"
type="javax.sql.DataSource"
driverClassName="org.sqlite.JDBC"
url="jdbc:sqlite:/${catalina.home}/dbs/yourDB.db"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory">
</Resource>
</Context>
Then add the following to WEB-INF/web.xml:
<resource-ref>
<description>Reviews Database</description>
<res-ref-name>jdbc/yourdb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
At this point, you should be good to go. Here is some sample code for accessing the database (I have a table 'admin' with a column 'username'):
public String getName() {
LOG.info("getting name : " + this.name);
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/yourdb");
Connection conn = ds.getConnection();
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("select username from admin");
this.name = rs.getString(1);
} catch (SQLException se) {
LOG.info(se.toString());
} catch (NamingException ne) {
LOG.info(ne.toString());
}
return this.name;
}
Note: some distros of tomcat don't come with tomcat.dbcp by default, if you run into problems it may be easier to reference the dbcp class that comes with commons, org.apache.commons.dbcp.BasicDataSourceFactory. I had this problem with tomcat.dbcp not included in my tomcat7 installation and once I switched the reference in context.xml everything was working fine.
What we did is pretty similar. Unfortunately you cannot create a SQLite Connection pool on Tomcat as SQLite has a database file for each user.
Just copy the jar file in TOMCAT_HOME/lib folder but you cannot call a connection via JNDI.
You will have to do something like this:
/**
*
* #param driverClassName
* #param url
* #param user
* #param password
* #throws SQLException
* #throws Exception
*/
public DefaultJdbcTransaction(String driverClassName, String url, String user, String password) throws SQLException {
super();
// TODO Auto-generated constructor stub
try {
Class.forName(driverClassName).newInstance();
if (user == null && password == null) {
connection = DriverManager.getConnection(url);
} else {
connection = DriverManager.getConnection(url, user, password);
}
} catch (InstantiationException e) {
// TODO Auto-generated catch block
throw new SQLException(e);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
throw new SQLException(e);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
throw new SQLException(e);
}
}
Where url="jdbc:sqlite:/path/to/sqlite/file/userId.db", driverClassName="org.sqlite.JDBC", and (user = password = null).
I'm using sqlitejdbc-v056.jar.
Hope this helps