How to troubleshoot problems when tomcat servlet connects to mysql - mysql

Tomcat servlet gets connection to mysql with getConnection(). Just fetch data from db test table shop.Connection to mysql is successful, but browser doesn't still show any data from backend. JavaScript shows request.status is 200 and request.readyState is 2 or 3. How can I find the problem? I even don't see any exceptions in tomcat log file.
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.println("ok");
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "***");
Statement statementQuery = connection.createStatement();
ResultSet set = statementQuery.executeQuery("select * from shop");
// connection.commit(); Error appears here(should be commented):
out.println("<div>");
while (set.next()) {
out.println("ok");
out.println(set.getInt(1) + " ");
out.println(set.getString(2) + " ");
out.println(set.getDouble(3));
}
} catch (Exception e) {
e.printStackTrace();
}
out.println("</div>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
doGet(request, response);
}
EDIT:
connection.commit() is wrong. Comment that line and it works.

Change Oracle driver to Mysql driver
Class.forName("com.mysql.jdbc.Driver");
SQL statements are executed sequentially. Change the order of execution to:
int ret = statement.executeUpdate("insert into shop values (53, 'fjd', 43.2)");
ResultSet s1 = statement.executeQuery("select * from shop");
Execute also a commit on the connection
connection.commit();
And add a finally to close statement and connection
}finally{
statement.close();
connection.close();
}

Related

Executed rollbackon connection

i am using JDBC to connect my MySQL database. I am trying to delete data from 2 tables (tasks and tasks_users(join table)). Look at my code:
#Override
public int deleteById(Long id) throws SQLException {
deleteByIdFromJoinTable(id);
int updated_rows;
sessionManager.beginSession();
try(Connection connection = sessionManager.getCurrentSession();
PreparedStatement statement = connection.prepareStatement(SQL_QUERIES.DELETE_TASK_BY_ID.QUERY)) {
statement.setLong(1, id);
updated_rows = statement.executeUpdate();
sessionManager.commitSession();
}catch (SQLException exception){
log.error(exception.getMessage(), exception);
sessionManager.rollbackSession();
throw exception;
}
return updated_rows;
}
public void deleteByIdFromJoinTable(Long id) throws SQLException {
sessionManager.beginSession();
try(Connection connection = sessionManager.getCurrentSession();
PreparedStatement statement = connection.prepareStatement(SQL_QUERIES.DELETE_TASK_FROM_TASKS_USERS.QUERY)) {
statement.setLong(1, id);
statement.executeUpdate();
sessionManager.commitSession();
}catch (SQLException exception){
log.error(exception.getMessage(), exception);
sessionManager.rollbackSession();
throw exception;
}
}
enum SQL_QUERIES {
DELETE_TASK_BY_ID("DELETE FROM tasks WHERE id=(?)"),
DELETE_TASK_FROM_TASKS_USERS("DELETE FROM tasks_users WHERE task_id=(?)");
final String QUERY;
SQL_QUERIES(String QUERY) {
this.QUERY = QUERY;
}
}
}
But when i call deleteById(), i get exception like:
13:58:03.079 [http-nio-8080-exec-9] DEBUG com.zaxxer.hikari.pool.ProxyConnection - restServiceDbPool - Executed rollback on connection com.mysql.cj.jdbc.ConnectionImpl#68421fee due to dirty commit state on close()
Connection to database works well, method, where i get all tasks returns them without problems.
What's problem is here, i will be very grateful for help?

IntelliJ cannot find MySQL JDBC driver

I have added MySQL JDBC driver but I keep getting the following error: No suitable driver found for jdbc.
Here's the code that I'm trying:
public class Test extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jsp1", "root", "");
System.out.println("Connected successfully");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here are the project settings.
As soon as I add MySQL jar, one following problem appears:
I have tried all of the three options above, but I keep getting the same error.

How to use where clause with session value in servlet

I have passed a value into servlet using a session.then assign the value to a variable call 'ms'. now i want to select data using that variable with 'where' clause. but it does not work.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
HttpSession ses=request.getSession(false);
String ms = ses.getAttribute("ma").toString();
try {
dbconn = new DatabaseConnection();
conn = dbconn.setConnection();
stmt = conn.createStatement();
query = "select * from person where Email ="+ms;
res = dbconn.getResult(query, conn);
while(res.next()){
lst.add(res.getString("Username"));
lst.add(res.getString("Title"));
lst.add(res.getString("Fname"));
lst.add(res.getString("Lname"));
}
res.close();
}catch(Exception e){
RequestDispatcher rd =request.getRequestDispatcher("myAccount.jsp");
rd.forward(request, response);
}finally{
request.setAttribute("EmpData", lst);
RequestDispatcher rd =request.getRequestDispatcher("myAccount.jsp");
rd.forward(request, response);
lst.clear();
out.close();
}
It's your query causing the exception.
Instead of
query = "select * from person where Email ="+ms;
You should quote the email parameter.
query = "select * from person where Email ='"+ms+"'";
But your code is vulnerable to SQL injection. It is better to use PreparedStatement for this.
By the way, it is also better to print the stack trace on catch clause, you could spot what exactly going wrong easily.

MySQL connection pooling with JERSEY

I'm developping a RESTful API with Jersey and MySQL.
I'm actually using the JDBC driver to connect to the database and I create a new connection everytime I want to acess it. As it clearly is a memory leakage, I started to implement the ServletContextClassclass but I don't know how to call the method when I need to get the result of a SQL query.
Here is how I did it wrong:
DbConnection.java
public class DbConnection {
public Connection getConnection() throws Exception {
try {
String connectionURL = "jdbc:mysql://root:port/path";
Connection connection = null;
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "password");
return connection;
}
catch (SQLException e) {
throw e;
}
}
}
DbData.java
public ArrayList<Product> getAllProducts(Connection connection) throws Exception {
ArrayList<Product> productList = new ArrayList<Product>();
try {
PreparedStatement ps = connection.prepareStatement("SELECT id, name FROM product");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Product product = new Product();
product.setId(rs.getInt("id"));
product.setName(rs.getString("name"));
productList.add(product);
}
return productList;
} catch (Exception e) {
throw e;
}
}
Resource.java
#GET
#Path("task/{taskId}")
#Consumes(MediaType.APPLICATION_JSON)
public Response getInfos(#PathParam("taskId") int taskId) throws Exception {
try {
DbConnection database= new DbConnection();
Connection connection = database.getConnection();
Task task = new Task();
DbData dbData = new DbData();
task = dbData.getTask(connection, taskId);
return Response.status(200).entity(task).build();
} catch (Exception e) {
throw e;
}
}
Here is where I ended up trying to implement the new class:
ServletContextClass.java
public class ServletContextClass implements ServletContextListener {
public Connection getConnection() throws Exception {
try {
String connectionURL = "jdbc:mysql://root:port/path";
Connection connection = null;
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "password");
return connection;
} catch (SQLException e) {
throw e;
}
}
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
DbConnection database = new DbConnection();
try {
Connection connection = database.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
//con.close ();
}
}
But problem is, I don't know what to do next. Any help? Thanks
You need to set the Connection variable as an attribute of the ServletContext. Also, I would recommend using connection as a static class variable so you can close it in the contextDestroyed method.
You can retrieve the connection attribute in any of your servlets later on for doing your DB operations.
public class ServletContextClass implements ServletContextListener {
public static Connection connection;
public Connection getConnection(){
try {
String connectionURL = "jdbc:mysql://root:port/path";
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "password");
} catch (SQLException e) {
// Do something
}
}
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
getConnection();
arg0.getServletContext().setAttribute("connection", connection);
}
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
try{
if(connection != null){
connection.close();
}
}catch(SQLException se){
// Do something
}
}
}
Finally access your connection attribute inside your Servlet (Resource). Make sure you pass #Context ServletContext to your Response method so you can access your context attributes.
#GET
#Path("task/{taskId}")
#Consumes(MediaType.APPLICATION_JSON)
public Response getInfos(#PathParam("taskId") int taskId, #Context ServletContext context) throws Exception {
try {
Connection connection = (Connection) context.getAttribute("connection");
Task task = new Task();
DbData dbData = new DbData();
task = dbData.getTask(connection, taskId);
return Response.status(200).entity(task).build();
} catch (Exception e) {
throw e;
}
}
Now that we have solved your current issue, we need to know what can go wrong with this approach.
Firstly, you are only creating one connection object which will be used everywhere. Imagine multiple users simultaneously accessing your API, the single connection will be shared among all of them which will slow down your response time.
Secondly, your connection to DB will die after sitting idle for a while (unless you configure MySql server not to kill idle connections which is not a good idea), and when you try to access it, you will get SQLExceptions thrown all over. This can be solved inside your servlet, you can check if your connection is dead, create it again, and then update the context attribute.
The best way to go about your Mysql Connection Pool will be to use a JNDI resource. You can create a pool of connections which will be managed by your servlet container. You can configure the pool to recreate connections if they go dead after sitting idle. If you are using Tomcat as your Servlet Container, you can check this short tutorial to get started with understanding the JNDI connection pool.

How to redirec to to HTML if exception occured

I've been trying to search for a way to redirect to an HTML file if a SQLException occurs. I'm going to give you an example.
I have my connection class something like this:
public class DBConection{
Connection con = null;
public DBConnection() throws RuntimeException{
try {
Class.forName("org.gjt.mm.mysql.Driver");
String user = "root";
String pass = "12345";
String db = "java";
con = DriverManager.getConnection("jdbc:mysql://localhost/" + db, user, pass);
}catch (ClassNotFoundException ex) {
throw new RuntimeException();
}catch (SQLException ex) {
throw new RuntimeException();
}
}
}
and I'm calling it from a Servlet class,
public class ElectionsServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String RETURN_PAGE = "index.jsp";
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
DBConnection con = new DBConnection();
response.sendRedirect(RETURN_PAGE);
}
}
If an error ocurres during the DBConnection I want to redirect it to my RETURN_PAGE. Can anybody help me?
Just use the builtin container managed exception handling facilities. You need to rethrow the caught exception as ServletException and define the error page as <error-page> in web.xml.
You only need to change your DB access logic accordingly. It's far from sane, safe and efficient. The exception handling is also strange. You seem to have ripped this from a completely outdated resource given the fact that you're using the deprecated MySQL JDBC driver class name.
Here's a basic kickoff example:
public final class Database {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost/java";
private static final String USER = "root";
private static final String PASS = "12345";
static {
try {
Class.forName(DRIVER);
}
catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError("The JDBC driver is missing in classpath!", e);
}
}
private Database() {
// Don't allow construction.
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASS);
}
}
Finally use and handle it in the servlet as follows:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
Connection connection = null;
// ...
try{
connection = Database.getConnection();
// ...
}
catch (SQLException e) {
throw new ServletException("DB fail!", e);
}
finally {
// ...
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
}
(better would be to wrap the DB job in a DAO class which in turn throws a SQLException, but that's a different problem)
And declare the error page in web.xml as follows:
<error-page>
<exception-type>java.sql.SQLException</exception-type>
<location>/WEB-INF/errorpages/database.jsp</location>
</error-page>
You can of course also use <location>/index.jsp</location> but that's not very friendly to the enduser as it's completely confusing why he returns back to there. Rather put that as a link in the database.jsp error page along with something user friendly like
Sorry, an unrecoverable problem has occurred while communicating with the DB. Please click the following link to return to the index page.
See also:
Show JDBC ResultSet in HTML in JSP page using MVC and DAO pattern
The question is already answered, but I'll add a few comments:
I don't see the need of catching SQLException and ClassNotFoundException only to rethow RuntimeException instances. If you're planning to do nothing when this exception raises in your DBConnection class, just add throws to your constructor signature. With that, the compiler will check that a try-catch block be added when using your constructor.
There's no need of adding throws RuntimeException to your constructor signature. RuntimeException is a non-checked exception.
Add try-catch block to your doPost method and if any exception occurs in try block, catch that exception and redirect to RETURN_PAGE.
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
try{
DBConnection con = new DBConnection();
}catch(Exception e){
response.sendRedirect(RETURN_PAGE);
}
}