Ejemplos consultas con Java y Mysql

Instalación de MySQL en Windows

No pretendo dar un tutorial completo para instalar MySQL. Símplemente contar el proceso de instalción que yo he seguido y que me ha funcionado bien para poder conectarme con MySQL desde java. No entro en demasiados detalles, puesto que la instalación en windows se hace prácticamente sola y no es necesario tocar casi nada de las opciones por defecto.




Descarga del programa:

Lo primero, descargarse MySQL de algún sitio. Yo lo he hecho de aqui: http://dev.mysql.com/get/Downloads/MySQL-4.1/mysql-4.1.10a-win32.zip/from/pick#mirrors
El fichero es un .zip con un Setup.exe dentro. Lo desempaqueto (aunque no hace falta) para tener el .exe más a mano.

Instalación:

Ejecuto el Setup.exe. Me sale una ventana que me permite elegir instalación por defecto o personalizada. Elijo instalación a medida, más que nada por ir viendo que opciones.
Aparece un arbol con las cosas a instalar. Dejo lo que viene por defecto, aunque veo que se pueden instalar ficheros de cabecera .h y librerías para poder acceder a MySQL desde C. Es un detalle a tener en cuenta. También elijo el directorio de instalación.
Pregunta si quiero configurar MySQL durante la instalación. Le contesto que sí. Selecciono "configuración detallada", que es la que viene por defecto.
Me da a elegir tres posibles tipos de máquina en la que instalar MySQL. Elijo la opción de máquina para desarrollo, que es la opción por defecto. Supuestamente el servidor MySQL en una máquina de desarrollo se configura de forma que consuma pocos recursos.
Me da a elegir el tipo de base de datos. Elijo base de datos multifuncional.
Me da a elegir la ubicación de las tablas de la base de datos. Dejo el directorio por defecto.
Me da a elegir el número de conexiones que va a admitir la base de datos. Dejo DSS/OLAP, para pocas conexiones, que es la opción por defecto.
Habitlio acceso a través de tpc/ip que está marcado por defecto y con el puerto por defecto 3306
Juego de caracteres por defecto.
Elijo instalar con servicio de windows y que lo lance automáticamente, todo ello está por defecto.
Le marco, que no lo estaba, para que incluya en el path tanto el cliente como el servidor de MySQL, y asi poder llamarlo desde línea de comandos. Esto es necesario para que otros programas (por ejemplo, un servidor apache con php) encuentren las librerías de MySQL cuando las necesiten.
Elijo pasword de root y dejo el resto por defecto (no acceso en remoto al root y no creo cuenta anónima).
He tenido que conectar a internet para que no fallara en la última parte de la instalación. No sé muy bien si es porque MySQL intenta acceder a Internet para algo o símplemente, porque como se instala como servicio, tiene que abrir un puerto de escucha de internet.

Creación de una base de datos, una tabla y un registro de prueba

Aunque MySQL crea una base de datos de prueba que llama "test", decido crearme mi propia base de datos, con mi propia tabla y un registro en ella.
Una vez instalado, me voy al menú de " inicio", "programas", "mysql", "MySQL Server 4.1",  "MySQL Command Line Client". Me sale una ventanita negra que me pide el password y trata de acceder a internet. Supongo que como la como la conexión es a través de red, necesita el acceso a internet. Meto la password de root/administrador que puse al instalar y me sale un "prompt" de MySQL.
Voy a crear una base de datos, con una tabla y una entrada de datos para poder acceder desde java.
mysql> create database prueba;
mysql> use prueba;
mysql> create table persona (id smallint auto_increment, nombre varchar(60), nacimiento date, primary key(id));
mysql> insert persona values (NULL, 'Pedro', '1995-09-12');

Conectarnos con la base de datos

Una vez que java tiene el jar accesible y sabe dónde encontrarlo, ya podemos empezar con el código. Lo primero es conectarse con la base de datos.



El código puede ser como este
import java.sql.Connection;
import java.sql.DriverManager;
...
try
{
   Class.forName("com.mysql.jdbc.Driver");
   Connection conexion = DriverManager.getConnection("jdbc:mysql://localhost/agenda", "root", "LA_PASSWORD");
   ...
En primer lugar hemos hecho los import adecuados para poder obtener la conexión.
Luego hay que asegurarse de que se inicializa el Driver y se registra. Para ello hay dos opciones. Hacer un new de él o bien instanciarlo con Class.forName("nombre de clase"), que es como hacer el new, pero de una forma rara.
La ventaja de hacerlo con Class.forName() es que sólo necesitaremos el Driver de una base de datos si lo usamos. Me explico. Imagina que haces un programa que permite permite conectarse con varias bases de datos distintas: MySQL, PostGres, Oracle, etc. En algún sitio damos a elegir al usuario qué tipo de base de datos tiene.
Si hacemos new de los Driver, tendremos que hacer unos if para en función de la elegida, hacer new de uno o de otro. El problema es que en nuestro código estarán los import y los new de todos los Driver de todas las bases de datos necesaras, los vayamos a usar o no. El programa no compilará y no correrá si no tiene todos los Driver accesibles.
/* Todos estos import son necesarios para que compilen los news correspondientes */
import driver_de_mysql;
import driver_de_postgres;
import driver_de_oracle;
...
if (ha_elegido_mysql)
   new driver_de_mysql();
if (ha_elegido_postgres)
   new driver_de_postgres();
if (ha_elegido_oracle)
   new driver_de_oracle();
Sin embargo, con Class.forName() no necesitamos el import. Haremos los mismos if de antes, pero usaremos simplemente String distintos para llamar a Class.forName(). No necesitamos los import y no necesitamos los jar con los Driver, salvo el jar con el Driver que realmente elija el usuario. Es cosa suya tener instalado SU driver de SU base de datos.
/* No hacen falta imports */
...
if (ha_elegido_mysql)
   Class.forName("driver_de_mysql");
if (ha_elegido_postgres)
   Class.forName("driver_de_postgres");
if (ha_elegido_oracle)
   Class.forName("driver_de_oracle");
Una vez que nos hemos asegurado que java tiene el Driver cargado, simplemente pediremos conexión con la base de datos a la clase DriverManager.
Connection conexion = DriverManager.getConnection("jdbc:mysql://localhost/agenda", "root", "LA_PASSWORD");
DriverManager tiene muchos métodos getConnection() con parámetros variados. Todos son variantes de lo mismo y la información que suministramos es la misma. Aquí hemos utilizado uno con tres parámetros String, que vamos a explicar.
  • url: Es una cadena que nos permite localizar la base de datos. Para mysql, el formato es "jdbc:mysql://ordenador_donde_corre_la_base_de_datos/nombre_base_datos". Donde se pone el nombre o IP del ordenador en el que se encuentra nuestro servidor de base de datos y el nombre de la base de datos. En nuestro ejemplo, tenemos el servidor de base de datos corriendo en el mismo ordenador que el programa java, por lo que ponemos localhost. La base de datos la he llamado agenda. El comando SQL para crear la base de datos agenda sería
    mysql> CREATE DATABASE agenda;
  • user: Un usuario válido para la base de datos.
  • password: La clave del usuario.
Si todo va bien, tendremos nuestra conexión a la base de datos. Si va mal, saltará una excepción. Por eso es importante (y obligatorio para que compile) meter todo esto en un try-catch.
Esta forma de obtener una conexión está bien para apliaciones sencillas, en el que únicamente se establece una conexión con la base de datos, no hay muchos hilos trabajando, etc. Si nuestra aplicación es algo más compleja/seria, en el que varios hilos pueden trabjar simultáneamente, en vez de obtner las conexiones directamente con DriverManager.getConnection(), es mejor obtenerlas a través de un Pool de Conexiones.

Creamos la tabla en Base de Datos ... y la borramos.

Para enviar comandos SQL a la base de datos, se usa la clase Statement de java. Esta clase se obtiene a partir de la conexión, de esta forma:
Statement st = conexion.createStatement();
por supuesto, dentro de un try-catch.
Statement tiene muchos métodos, pero hay dos interesentantes: executeUpdate() y executeQuery(). El primero se usa para sentencias SQL que impliquen modificaciones en la base de datos (INSERT, UPDATE, DELETE, etc). El segundo sólo para consultas (SELECT y similares).
Nuestra creación de tabla afecta a la base de datos, así que con executeUpdate().
st.executeUpdate("CREATE TABLE contacto (id INT AUTO_INCREMENT, PRIMARY KEY(id), nombre VARCHAR(20), apellidos VARCHAR(20), telefono VARCHAR(20))");
Esto crea una tabla contacto con cuatro campos: idnombreapellidos y telefono.
Para borrar la tablita esta, lo mismo, pero con DROP en vez de CREATE.
st.executeUpdate("DROP TABLE contacto");

Insertar datos en la base de datos

Vamos a hacer un esfuerzo de imaginación y supongamos que no hemos borrado la tabla contacto, que sigue existiendo en base de datos. Vamos a meterle datos.
String nombres[]={"Juan","Pedro","Antonio"};
String apellidos[]={"Gomez","Lopez","Alvarez"};
String telefonos[]={"123","456","789"};
...
for (int i=0;i<nombres.length;i++)
   st.executeUpdate("INSERT INTO contacto (nombre, apellidos, telefono) VALUES ('"+nombres[i]+"','"+apellidos[i]+"','"+telefonos[i]+"' )");
también en un try-catch.
He puesto los datos a insertar en unos arrays. Tú puedes recogerlos de un sitio con más sentido. Por ejemplo, si es una agenda de contactos, lo mejor es pedírselos al usuario. Yo, por simplicidad y porque para el ejemplo va que chuta, los pongo en un array y con un bucle los voy insertando.
Fíjate que la sentencia INSERT se va componiendo a base de sumar cadenas. Sería más eficiente con un StringBuffer, pero así se simplifica algo el ejemplo.
Fíjate que en el INSERT metemos comillas simples para los valores de cadenas, es decir, en nombreapellidos y telefono. El INSERT sería, de verdad, así
INSERT INTO contacto (nombre, apellidos, telefono) VALUES ('Juan', 'Gomez', '123');
Ahí se ven más claras las comillas simples para los datos que definimos como VARCHAR en la creación de la tabla, es decir, JuanGomez y 123. Por eso en el código las hemos puesto
...VALUES ('"+nombres[i]+"','"...
Si fuesen datos numéricos no harían falta, son cosas de SQL, pero tenemos que tener cuidado de componerlas bien.

Consultar datos de la base de datos

Vamos a hacer ahora una consulta de los datos que acabamos de insertar en la base de datos. Las consultas se hacen con executeQuery() y nos devolverán unResultSet.
El ResultSet de alguna forma representa una conexión hacia los datos. En el ResultSet NO están todavía los datos. Según se los vayamos pidiendo, los irá trayendo de base de datos. Esto quiere decir que si una consulta devuelve muchos resultados, no se nos va a llenar la memoria por el hecho de hacer la consulta.
Para traer el primer resultado, debemos llamar el método next() del ResulSet. Para el siguiente otro next() y así sucesivamente hasta que next() devuelva false, indicando que ya no quedaban datos. El código puede ser así
ResultSet rs = st.executeQuery("SELECT * FROM contacto");
while (rs.next())
{
   System.out.println("nombre="+rs.getObject("nombre")+
      ", apellidos="+rs.getObject("apellidos")+
      ", telefono="+rs.getObject("telefono"));
}
rs.close();
Hemos hecho un SELECT para obtener los datos. Luego un bucle while(rs.next()), es decir, mientras next() vaya trayendo resultados.
Después de next(), el resultado recién traido está disponible en el ResulSet. La forma de recoger los campos es pedirlos con algún método get(). Si sabemos de qué tipo es el dato, podemos pedirlo con getInt()getString(), etc. Si no lo sabemos o nos da igual (como en este caso), bastará con un getObject(), capaz de traer cualquier tipo de dato.
En estos métodos get() podemos pasar como parámetro un entero, empezando en 1, que es el número del campo en el SELECT. Es decir, si hacemos SELECT campo1, campo2, campo3 ..., si pedimos getObject(1) obtenemos el valor de campo1, para getObject(2) el de campo2, etc.
Otra opción que a mi me gusta más, es pasar el nombre del campo, como se muestra en el código. Así, en el ejemplo de antes, getObject("campo1") nos devuelve el valor del campo1.

Update en la base de datos

Para UPDATE usamos executeUpdate(). Vamos a cambiar el número de teléfono de Juan. Ya que en la tabla hemos puesto un campo id, vamos primero a obtener el id de Juan para luego usarlo en el UPDATE. Esto no tiene por qué ser así, es sólo el ejemplo.
Para obtener el id:
rs = st.executeQuery("SELECT id FROM contacto WHERE nombre='Juan'");
rs.next();
int id = rs.getInt("id");
Es un SELECT para obtener el campo id de Juan. Con rs.next() hacemos que venga el primer resultado de la consulta (y único en nuestro ejemplo). Como sabemos que es un INT, lo recogemos con getInt() y lo guardamos.
Para hacerlo bien, deberíamos ver si rs.next() devuelve o no resultado (quizás no haya nadie que se llame Juan en la base de datos) o si devuelve más de uno (más de un Juan en la base de datos), pero no vamos a complicarnos la vida en este ejemplo sencillo.
Ahora, sabiendo el id, podemos hacer el UPDATE.
st.executeUpdate("UPDATE contacto SET telefono='111' WHERE id="+id);
Esta vez, como el campo id es numérico, no hemos puesto las comillas simples.

Borrar datos de la base de datos

El borrado se hace con DELETE y executeUpdate(). Vamos a borrar a Pedro, que nos hemos peleado con él. Obtenemos primero su id, igual que antes.
rs = st.executeQuery("SELECT id FROM contacto WHERE nombre='Pedro'");
rs.next();
id = rs.getInt("id");
y ahora lo borramos
st.executeUpdate("DELETE FROM contacto WHERE id="+id);

Cerramos conexiones

Los ConnectionStatement y ResultSet con conexiones abiertas con base de datos. Debemos cerrarlas.
ResultSet se cierra solo cuando hacemos otra llamada execute() al Statement del que obtuvimos este ResultSet o bien cuando el recolector de basura "recolecta" al ResultSet. No nos preocupa en principio que se quede abierto, porque se acabará cerrando solo.
Eso sí, no podemos hacer nada con el Statement hasta que hayamos terminado con el ResultSet o se nos cerrará. Si necesitamos realizar otra cosa con base de datos, debemos crear otro Statement distinto.
Cuando terminemos con el Statement, lo cerramos con st.close().
Cuando terminemos con la Connection, la cerramos con conexion.close().

Ejemplo básico de MySQL con Java

Una vez instalado MySQL, descargado el driver para java de MySQL y con una base de datos y una tabla creada en MySQL, vamos a hacer un pequeño programa en java que nos permita conectarnos a la base de datos MySQL y consultar la tabla que hemos creado.

Instalar el Driver

En nuestro programa java, todos los import que necesitamos para manejar la base de datos están en java.sql.*. Puesto que casi todas los métodos relativos a base de datos pueden lanzar la excepción SQLException, meteremos todo nuestro programa en un try-catch.
Además, necesitamos la clase org.gjt.mm.mysql.Driver que viene con el driver de MySQL. Por ello, en nuestro CLASSPATH o incluido en nuestro proyecto con nuestro IDE favorito, debemos incluir el jar que contiene el driver MySQL (mysql-connector-java-3.1.7-bin.jar) o la versión más moderna y compatible con la versión de nuestro servidor de MySQL.
Lo primero que tenemos que hacer es asegurarnos que el Driver se inicializa y se registra, para ello
try
{
   Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e)
{
   e.printStackTrace();
}

Establecer la conexión con la base de datos

Debemos tener el servidor de MySQL arrancado. Si hemos instalado y dejado esa opción como estaba, cada vez que encendamos el ordenador, se arrancará el servidor de MySQL, por lo que no tenemos que preocuparnos por ello.
El servidor de MySQL abre por defecto el puerto 3306 para aceptar conexiones de posibles clientes, de programas que quieran conectarse y acceder a la base de datos. Nuestro programa java, si quiere consultar la tabla de base de datos que hemos creado, deberá conectarse a este servidor.
Para establecer la conexion, la clase DriverManager tiene métodos getConnection(). Usaremos uno de ellos
// Establecemos la conexión con la base de datos. 
Connection conexion = DriverManager.getConnection ("jdbc:mysql://localhost/prueba","root", "la_clave");
El primer parámetro del método getConnection() es un String que contiene la url de la base de datos:
  • jdb:mysql porque estamos utilizando un driver jdbc para MySQL, que es el que nos hemos bajado.
  • localhost porque el servidor de base de datos, en mi caso, está en el mismo ordenador en el que voy a correr el prorama java. Aquí puede ponerse una IP o un nombre de máquina que esté en la red.
  • prueba es el nombre de la base de datos que he creado dentro de mysql. Se debe poner la base de datos dentro del servidor de MySQL a la que se quiere uno conectar. Es el nombre que pusimos cuando desde SQL hicimos create database prueba;
Los otros dos parámetros son dos String. Corresponden al nombre de usuario y password para acceder a la base de datos. Al instalar MySQL se crea el usuario root y se pide la password para él. Como no hemos creado otros usuarios, usaremos este mismo.
Si todo va bien, en conexion tendremos nuestra conexión a la base de datos.
Esta conexión es en realidad un socket entre java y la base de datos, aunque para nosotros es transparente. Lo que sí es importante, es saber que si varios hilos comparten esta conexión, deben usarla sincronizadamente. Si no se hace así, los mensajes que van por el socket se pueden entremezclar y los hilos pueden leer cachos de mensaje destinados al otro hilo. Otra opción es que cada hilo cree su propia conexión. Finalmente, la mejor opción de todas si nuestra aplicación va a tener varios hilos intentando acceder a la base de datos, es usar un Pool de conexiones.

Realizar una consulta

Para realizar cualquier acción sobre la base de datos (consulta, insertar nuevos registros, modificar los existentes o borrar), necesitamos una clase Statement. Para obtenerla, se le pide dicha clase a la conexión. La forma de hacerlo, para una consulta, es la siguiente:
// Preparamos la consulta 
Statement s = conexion.createStatement();
ResultSet rs = s.executeQuery ("select * from persona");
La parte de createStatement() no tiene ningú secreto, salvo que puede lanzar una excepción que hay que capturar.
El Statement obtenido tiene un método executeQuery(). Este método sirve para realizar una consulta a base de datos.
  • El parámetro que se pasa en un String en el que está la consulta en lenguaje SQL. No hace falta terminarlo con punto y coma. En nuestro caso "select * from persona". siendo persona el nombre que hemos puesto a la tabla en la base de datos.
  • El resultado nos lo devuelve el método como un ResultSet. Este ResultSet no es más que una clase java similar a una lista en la que está el resultado de la consulta. Cada elemento de la lista es uno de los registros de la base de datos. En realidad, ResulSet no contiene todos los datos, sino que los va consiguiendo de la base de datos según se van pidiendo. Por ello, el método executeQuery() puede tardar poco, pero el recorrer los elementos delResultSet no es tan rápido. De esta forma se evita que una consulta que dé muchos resultados tarde mucho tiempo y llene la memoria del programa java.

Leer los resultados

El ResultSet contiene dentro los registros leidos de la base de datos. Inicialmente, tal cual nos lo devuelve el Statement.executeQuery(), tiene internamente un "puntero" apuntando justo delante del primer registro. El método next() del ResultSet hace que dicho puntero avance al siguiente registro, en este caso, al primero. Si lo consigue, el método next() devuelve true. Si no lo consigue (no hay siguiente registro que leer), devuelve false.
Por tanto, una forma de ir leyendo los registros en meternos en un while.  
// Recorremos el resultado, mientras haya registros para leer, y escribimos el resultado en pantalla. 
while (rs.next())
{
    System.out.println (rs.getInt (1) + " " + rs.getString (2)+ " " + rs.getDate(3));
}
Una vez que el "puntero" está apuntando a un registro, los métodos getInt()getString()getDate(), etc nos van devolviendo los valores de los campos de dicho registro. Podemos pasar a estos métodos un índice (que comienza en 1) para indicar qué columna de la tabla de base de datos deseamos. También podemos usar un String con el nombre de la columna (tal cual está en la tabla de base de datos).
Es responsabilidad nuestra saber qué tipo de dato hay en cada columna, aunque si nos equivocamos y RecordSet es capaz de hacer la conversión, la hará por nosotros. Por ejemplo, en cualquiera de los campos anteriores podemos pedir un getString() y nos devolveran los números como String y la fecha como String.
También podemos usar getObject(), y el RecordSet nos devolverá el Object más adecuado para el tipo de campo que pedimos.

Cerrar la conexión

Una vez que terminamos de usar la conexión, se debería cerrar, o bien terminar el programa, con lo que se cierra automáticamente.
// Cerramos la conexion a la base de datos. 
conexion.close();

El ejemplo

En PruebaMySQL.java tienes el ejemplo completo. Debes quitarle la extensión txt y meterlo en un árbol de directorios que sea chuidiang\ejemplos\base_datos
Vamos ahora a ver ahora cómo meter los resultados de la consulta en un JTable.

No hay comentarios:

Publicar un comentario

Gracias por comentar en mi blog. Saludos.