style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

MySql Connector/J

Buenas tardes,

Estoy creando un Dinamic Web Project en Eclipse, quiero hacer pruebas JSP con MySql, pero no se como, en el mismo proyecto ya hice la prueba de crear una clase Conector y una clase prueba para probar la conexión y todo marcha bien, la forma de en la que estoy realizando el JSP es esta:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ page import="java.sql.*" %>
<%@ page import="conector.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Books Store</title>
</head>
<body>
<%
try {
        Conector2 c = new Conector2("localhost","books", "root","");
        Statement s = c.getConector().createStatement();
        ResultSet rst = s.executeQuery("Select * from books_details");
while(rst.next()){
        out.print(rst.getInt("id"));
}

}
catch(SQLException sqle) {
        sqle.printStackTrace();
}
                %>
</body>
</html>

Pero me marca el siguiente error:

exception

org.apache.jasper.JasperException: java.lang.NullPointerException
root cause

java.lang.NullPointerException

importe mysql-connector-java-5.1.13.jar a mi proyecto.

Clase conector2

package conector;

import java.sql.*;

public class Conector2 {
        Connection c;

        public Conector2(String host, String db, String user, String pass) {           
                String url = "jdbc:mysql://" + host + ":3306/" + db + "";              
                try {          
                                Class.forName("com.mysql.jdbc.Driver");
                                c = DriverManager.getConnection(url, user, pass);
                } catch (ClassNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch(SQLException se) {
                        // TODO Auto-generated catch block
                        se.printStackTrace();
                }                      
        }
        public Connection getConector() {
                return c;
        }
}

Agradecería mucho me puedan ayudar con este problema.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

finally, etc

Eventualmente si piensas poner esto a funcionar en un ambiente donde puedes recibir muchas invocaciones al web service al mismo tiempo, necesitas manejar mejor tus excepciones (o más bien dicho, manejarlas, porque actualmente no las manejas, solamente las cachas y las imprimes). De hecho sospecho que el DriverManager.getConnection() está arrojando alguna excepción y por lo tanto la conexión (la variable c del Conector2) queda nula y la NPE se arroja en el c.getConector().getStatement() del JSP.

No es nada recomendable crear una conexión en un web service como lo estás haciendo porque en un ambiente de alta concurrencia te vas a quedar sin conexiones (y no estás manejando ese caso). Tampoco estás manejando los casos de que ocurra un error ya que tienes la conexión; necesitas tener un bloque finally para cerrarla SIEMPRE:

Conexion c = null;
try {
  //aqui obtienes tu conexion
} catch (SQLException ex) {
  //aqui manejas la excepcion, presentando error al usuario, haciendo rollback, etc segun el caso
} finally {
  if (c != null) {
    c.cerrar(); //Con esto aseguras que SIEMPRE se cierra la conexion
  }
}

Si no haces lo anterior, las conexiones luego se van quedando abiertas cuando hay algun error y luego ya no sabes ni por qué ya no puedes correr el web service si solamente eres el único usuario de la base de datos de desarrollo pero después de trabajar un rato con algun error, ya no te deja conectarte.

Imagen de francisco.santiagoj

Bean

Gracias Ezamudio,

La única forma en la que he podido acceder a la BD es fue creando un Bean y mediante este manejar la conexión, queda de la siguiente forma mi jsp y mi Bean de conexión, agradecería mucho me dieras tus comentarios para saber si es esta la forma correcta de conectar a la BD.

jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ page import="java.sql.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<jsp:useBean id="conector" class="conector.ConectorBean" scope="session"></jsp:useBean>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Books Store</title>
</head>
<body>
<%             
        try {
                conector.setUrl("10.152.142.201","books", "root","");
                Statement s = conector.getConector().createStatement();
                ResultSet rst = s.executeQuery("Select * from books_details");
                while(rst.next()){
                        out.print(rst.getInt("id"));%><br><%
                }
        }
        catch(SQLException sqle) {
                sqle.printStackTrace();
        }
        finally {
                conector.cerrar();
        }
                %>
</body>
</html>

ConectorBean

package conector;
import java.sql.*;

public class ConectorBean {
        private String host;
        private String dataBase;
        private String username;
        private String password;       
        private Connection conector;   

        public Connection getConector() {
                creaConector();
                return conector;
        }
        public void setUrl(String host, String dataBase, String username, String password) {
                this.host = host;
                this.dataBase = dataBase;
                this.username = username;
                this.password = password;
        }
        private void creaConector(){
                String url = "jdbc:mysql://" + host + ":3306/" + dataBase + "";        
                try {          
                                Class.forName("com.mysql.jdbc.Driver");                        
                                conector = DriverManager.getConnection(url, username, password);
                                System.out.println("Se creo la conexion ");
                } catch (ClassNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch(SQLException se) {
                        // TODO Auto-generated catch block
                        se.printStackTrace();
                }                      
        }
        public void cerrar() {         
                        if(conector != null) {
                                try {
                                        conector.close();
                                } catch (SQLException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                }
                        }              
        }
}

Saludos

Imagen de francisco.santiagoj

Error

No había hecho pruebas, pero de si pongo finally en el Bean creo que la conexión se cierra antes de mostrarme la información.

Imagen de francisco.santiagoj

Cambios

Para no hacer larga la pagina modifique los últimos códigos, ahora funciona, pero no se si sea la mejor forma de hacerlo.

Saludos

Imagen de ezamudio

Bean

Cuál es la finalidad de ese bean? Lo único que hace es guardar los parámetros de conexión (que ya tienes en tu JSP), crear la conexión (sin manejar las excepciones) y cerrarla.

En tu JSP:

                Statement s = conector.getConector().createStatement();
                ResultSet rst = s.executeQuery("Select * from books_details");

Cada vez que se invoca ese código, lo que pasa en tu bean es que se crea una conexión nueva, se guarda como variable de instancia y se devuelve (a menos que ocurra una excepción, en cuyo caso la referencia a la variable conexion NO SE ACTUALIZA en tu bean, sino que se queda con la conexion anterior). Ese bean no es thread-safe. Pero por ahora concentrémonos en otro problema: si al realizar la conexión nueva en el método creaConector() ocurre un error, solamente se imprime quién sabe dónde, pero el método devuelve una de dos cosas: null, si es la primera invocación a ese método en el bean, o una conexión que probablemente ya no sirve o se encuentra en un estado inválido, si es que ya se ha invocado el método antes.

Si el método devuelve null, La primera línea de código en el JSP, donde quieres obtener un Statement, va a arrojar NPE porque el resultado de conector.getConector() es null y a eso le invocas createStatement().

Tienes dos opciones: primero obtener la pura conexión en el JSP y verificar que existe (que no es nula), o arrojar una excepción en el método que crea la conexión en el bean. En tu JSP de todas maneras vas a realizar operaciones que arrojan SQLException, entonces, cuál es la finalidad de cachar esa excepción en el método creaConector()? además ni la estás manejando; lo mejor será que no la caches, simplemente declárala (y también la vas a tener que declarar en getConector()). De esa forma, si por alguna razón no se puede obtener la conexión, se va a ejecutar el catch pero del JSP (donde tampoco haces nada todavía, pero bueno, ya vas a obtener una SQLException y no una NPE).

Imagen de francisco.santiagoj

Lo sospechaba

Sospechaba eso, pues de lo que he estudiado decía eso, el Bean es una referencia que se crea una vez que se ingresa y así se mantiene, encontré un ejemplo que probé y funciona, solo que no se donde poner el finally creo que esta es una forma mas fácil pero no se si es la mejor.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ page import="java.sql.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%
        String driver = "org.gjt.mm.mysql.Driver";
        Class.forName(driver).newInstance();
        Connection con = null;
        ResultSet rst = null;
        Statement stmt = null;
    try {      
                String url="jdbc:mysql://10.152.142.201/books?user=root&password=";    
                con=DriverManager.getConnection(url);
                stmt=con.createStatement();
        }
    catch(Exception e) {
                System.out.println(e.getMessage());
        }
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Books 2</title>
</head>
<body>
<%
        rst = stmt.executeQuery("select * from books_details");
        while(rst.next()) {
                out.print(rst.getInt("id"));   
        }      
%>     
</body>
</html>

Nuevamente, gracias.

Imagen de ezamudio

finally

El finally sólo puede ir donde debe ir. Un bloque try-catch-finally debe ir en ese orden: Primero un bloque de código rodeado por el try, luego uno o varios bloques de catch, siempre primero desde las excepciones más específicas hacia las más genéricas, y luego un solo finally.

Este último código tiene al final un segmento de código que arroja SQLException pero no lo rodeas con try-catch-finally. Eso compila bien? Tiene un rato que no uso JSP's así solitos. Pero pues sigues teniendo el mismo problema de raíz: La variable con puede ser nula al momento de ejecutar el executeQuery, porque la variable stmt sea nula, porque el DriverManager.getConnection() falla porque no puede crear la conexión a MySQL.

Se considera mala práctica cachar Exception, sobre todo con lo que estás haciendo, que es sólo imprimir el mensaje de la excepción al STDOUT, que para el caso es lo mismo (yo diría que incluso es peor) que no hacer nada. Si te ocurre NPE o SQLException o OutOfMemoryError o ClassNotFoundException o cualquier otra cosa no vas a poder distinguir porque sólo imprimes el mensaje, ni siquiera sabes qué clase de excepción fue ni sabes exactamente dónde ocurrió porque no vas a poder ver el stack trace. Y más adelante en tu código puede arrojarse una NPE porque stmt es null debido a alguna otra excepción en la línea donde obtienes el stmt o la anterior donde obtienes la conexión.

Imagen de francisco.santiagoj

catch

Gracias ezamudio, entonces las mejores practicas son cachar cada una de excepciones que puedan lanzarse y hacer algo con ellas para "amortiguar el golpe"?. Voy a intentar darle mas forma al código para que, si no es mucha molestia me des tus comentarios, seguiré revisando ejemplos y códigos para no estar posteando código a lo loco.

Saludos

Imagen de ezamudio

excepciones

Solamente debes cachar las excepciones que puedes manejar, las que sea pertinente que manejes. No vas a estar cachando un error de memoria insuficiente en el JSP, porque realmente no hay nada que puedas hacer al respecto. Con las excepciones declaradas no tienes otra opción más que cacharlas (y manejarlas realmente) o declararlas (y que sean problema de quien invoque el método donde las declaras).

En aplicaciones web siempre es bueno que manejes un DataSource en vez de crear una conexión a la base de datos en el JSP. Esto es porque si hay 1000 usuarios viendo ese JSP, no vas a poder crear mil conexiones a la base de datos. Si manejas primero un DataSource normal (ojo, hablo de manejarlo desde el JSP, o sea tenerlo como un componente en tu aplicación, no que vayas a crear el DataSource en el JSP porque sale igual), ya después puedes cambiar a usar un pool de conexiones a la base de datos, que por lo general funcionan dándote como interfaz un DataSource para que sea transparente su uso.

En tu último ejemplo lo que deberías tener es el segundo segmento de código dentro del try-catch del primero. Todo junto. Pero acomoda el HTML para que te sirva. Ese es el problema de usar JSP; terminas mezclando y enredando muchísimo el código con la interfaz gráfica (el HTML en este caso).

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">