8 de marzo de 2013

Procedimientos Almacenados y Vistas en MySQL-Java

En esta entrada se utilizaran procedimientos almacenados para ingresar, modificar y eliminar datos de empleado de una tabla en MySQL, ademas se utilizara una vista para mostrar los datos de todos los empleados en un Jtable, para esto tomaremos como base la estructura del formulario y el código utilizado en http://pabletoreto.blogspot.com/2013/02/acme-con-java-mysql-utilizando-ide.html

La tabla que se utilizara esta en la base se llama empleado la cual tiene 5 campos y esta en la base de datos registro, muestro la información correspondiente desde la consola de MySQL


Estructura de la aplicación
La aplicación se desarrollara en NetBeans 7.2., se crearan dos paquetes, uno llamado ConexionMySQL que tendrá una clase conexion.java con un método Conectar que servirá para conectarnos a la base de datos, este devolverá un objeto del tipo Connection.

También se creara un paquete llamado Formulario y dentro de este agregaremos un formulario JForm con nombre Java_MySQL.java que sera la interfaz de interacción con el usuario y que importara desde el paquete ConexionMySQL al método Conectar, ademas se debe recordar el importar el connector de MySQl en las librerías de nuestra aplicación, la estructura de la aplicación queda así:


Diseño del JForm(Package Formulario) 
A continuación presento el formulario que se utilizara con los nombres de los JText asi:
El label Código Empleado utiliza el txtCodigo
El label Nombres Empleado utiliza el txtNombres
El label Cargo Empleado utiliza el txtCargo
El label Departamento utiliza el txtDepartamento
El label Jefe asignado utiliza el txtJefe


Procedimientos Almacenados y Java
Presentare los procedimientos almacenados para los eventos de los botones Ingresar Datos, Modificar Datos y Eliminar Datos, para estas sencillas acciones no deberían utilizarse procedimientos almacenados a menos de querer tener una seguridad tan fuerte que termine siendo tosca e innecesaria, pero cada quien maneja su capa de datos como mejor le parezca, ademas usare commit en los procedimientos almacenados para el caso de realizar mas acciones sobre diferentes tablas, que es el uso real que debe darsele a los procedimientos almacenados.

Librerías y variables necesarias(Package Formulario)
Estas son las librerías y variables que utilizare en este ejemplo

package Formulario;
import ConexionMySQL.Conexion;
import java.sql.*;
import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;

public class Java_MySQL extends javax.swing.JFrame {
   
String Insertar="CALL InsertarDatos(?,?,?,?,?)";
String Modificar="CALL ModificarDatos(?,?,?,?,?)";
String Eliminar="CALL BorrarDatos(?)";
DefaultTableModel modelo;

    public Java_MySQL() {
        initComponents();
        CargarDatos();
    }

Conexión a la base de datos empleado en MySQl(Package ConexionMySQL).
No conectaremos a una base de datos en MySQL y usaremos el connector JDBC de MySQL, cualquier duda los remito a este link http://pabletoreto.blogspot.com/2013/02/acme-con-java-mysql-sin-gui.html

Este es el código a utilizar, recordar que esta en un paquete llamado ConexionMySQL, y se creo una clase llamada Conexion con un método publico llamado Conectar() que devuelve un objeto tipo
java.sql.Connection

package ConexionMySQL;
import java.sql.*;
import javax.swing.JOptionPane;

public class Conexion {
   static String user="root";
   static String pass="";
   static String url="jdbc:mysql://localhost/registro";
   static Connection cnn;
  
   public static Connection Conectar(){
           try{
           Class.forName("com.mysql.jdbc.Driver");
           cnn=DriverManager.getConnection(url,user,pass);
           }catch(ClassNotFoundException cnfex){
    JOptionPane.showMessageDialog(null, "ConexionMySQL:" +cnfex.getMessage());
           }catch(SQLException sqlex){
    JOptionPane.showMessageDialog(null, "ConexionMySQL:" +sqlex.getMessage());
           }catch(Exception ex){
    JOptionPane.showMessageDialog(null, "ConexionMySQL:" +ex.getMessage());
           }
           return cnn;
      }}

Mostrando los datos de la tabla empleado(Package Formulario)
Para mostrar los datos de la tabla empleado no se usara un procedimiento almacenado sino mas bien se construirá una vista en MySQL, se usara la sentecia: select * from empleado, como sugerencia, no se debe evitar en lo posible utilzar el * en sentencias select, pero en este ejemplo se utiliza sobre todo para mostrar la construcción y el uso de las vistas MySQL en Java, ustedes pueden construir una vista mas digna de su
proyecto o acorde a sus necesidades, pero aquí vamos a los simple, este es el código:

DELIMITER $$
USE `registro`$$
DROP VIEW IF EXISTS `seleccionardatos`$$

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `seleccionardatos` AS 
SELECT
  `empleado`.`Codigo`       AS `Codigo`,
  `empleado`.`Nombres`      AS `Nombres`,
  `empleado`.`Cargo`        AS `Cargo`,
  `empleado`.`Departamento` AS `Departamento`,
  `empleado`.`Jefe`         AS `Jefe`
FROM `empleado`$$

DELIMITER ;
La tabla se poblara con los datos cada vez que se inicie la aplicación y cada vez que se haga una acción sobre la base de datos, esto lo hará el método CargarDatos()

public void CargarDatos(){
            Connection cnn;    
            modelo= new DefaultTableModel();  
        try{
            cnn=Conexion.Conectar();
            Statement smt=cnn.createStatement();
            ResultSet rs= smt.executeQuery("select * from seleccionardatos");
            ResultSetMetaData md=rs.getMetaData();
            int columnas= md.getColumnCount();
            for (int i = 1; i <= columnas; i++) {
            modelo.addColumn(md.getColumnLabel(i));}
            while(rs.next()){
            Object[] fila = new Object[columnas];
            for (int i = 0; i < columnas; i++) {fila[i]=rs.getObject(i+1);}
            modelo.addRow(fila);
         //   fila=null;
            }
            tablita.setModel(modelo);
            cnn.close();
        }catch(SQLException sqlex){
            setTitle("Problema CargarDatos" +sqlex.getMessage());
        }}

Ingresar datos a la tabla empleado(Package Formulario)
Primero mostrare el procedimiento almacenado en MySQL para ingresar datos a la tabla empleado

DELIMITER $$
USE `registro`$$
DROP PROCEDURE IF EXISTS `InsertarDatos`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `InsertarDatos`(IN Codigo INT, Nombres VARCHAR( 50 ), Cargo VARCHAR( 50 ), Departamento VARCHAR( 50 ), Jefe VARCHAR( 50 ))
    READS SQL DATA
BEGIN
    DECLARE error INT;
START TRANSACTION;    
    INSERT INTO empleado VALUES(Codigo, Nombres, Cargo, Departamento, Jefe);
SET error=(SELECT @error);
IF(error=0)THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
    END$$

DELIMITER ;

Ahora presento el evento click del botón Ingresar Datos, este invoca al método IngresarDatos() y le envía los parámetros necesarios para realizar la operación de agregar datos sobre la tabla empleado

private void BIngresarActionPerformed(java.awt.event.ActionEvent evt) {
       String resultado;
        int codigo= Integer.parseInt(txtCodigo.getText());
        String nombres=txtNombres.getText();
        String cargo=txtCargo.getText();
        String departamento=txtDepartamento.getText();
        String jefe=txtJefe.getText();
        resultado=IngresarDatos(codigo, nombres, cargo, departamento, jefe);
        setTitle(resultado);
        CargarDatos();
    }

y por ultimo el método IngresarDatos() que se conecta con la base de datos, se utilizara este string: String Insertar="CALL InsertarDatos(?,?,?,?,?)"; para invocar al procedimiento almacenado InsertarDatos y se prepara la sentencia CallableStatement  para envíar los datos necesarios al procedimiento y agregar el registro correspondiente de la tabla empleados, al final refrescara el JTable con los nuevos datos de la tabla empleado.

public String IngresarDatos(int codigo, String nombres, String cargo, String dpto, String jefe){
            Connection cnn;    
            String resultado;
        try{
           cnn=Conexion.Conectar();
           CallableStatement cmst= cnn.prepareCall(Insertar);
           cmst.setInt(1,codigo);
           cmst.setString(2,nombres);
           cmst.setString(3,cargo);
           cmst.setString(4, dpto);
           cmst.setString(5, jefe);
           cmst.execute();    
           resultado="Los datos se ingresaron exitosamente !!!";
           cnn.close();        
        }catch(SQLException sqlex){
           resultado="No se realizo la operacion" +sqlex.getMessage();
        }catch(Exception ex){System.out.println(ex.getMessage());
           resultado="No se realizo la operacion" +ex.getMessage();
        }return resultado;
    }

Modificar datos a la tabla empleado(Package Formulario)
Primero mostrare el procedimiento almacenado en MySQL para modificar datos en la tabla empleado

DELIMITER $$
USE `registro`$$
DROP PROCEDURE IF EXISTS `ModificarDatos`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `ModificarDatos`(IN CodigoM INT, NombresM VARCHAR(50), CargoM VARCHAR(50), DepartamentoM VARCHAR(50), JefeM VARCHAR(50))
BEGIN
    DECLARE error INT;
    START TRANSACTION;
UPDATE empleado SET Nombres=NombresM, Cargo=CargoM, Departamento=DepartamentoM, Jefe=JefeM WHERE Codigo=CodigoM;
SET error=(SELECT @error);
IF(error=0)THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
    
END$$

DELIMITER ;

Ahora presento el evento click del botón Modificar Datos, este invoca al método ModificarDatos() y le envía los parámetros necesarios para realizar la operación de modificación sobre la tabla empleado

private void BModificarActionPerformed(java.awt.event.ActionEvent evt) {
        String resultado;
        int codigo= Integer.parseInt(txtCodigo.getText());
        String nombres=txtNombres.getText();
        String cargo=txtCargo.getText();
        String departamento=txtDepartamento.getText();
        String jefe=txtJefe.getText();
        resultado=ModificarDatos(codigo, nombres, cargo, departamento, jefe);
        setTitle(resultado);
        CargarDatos();
    }

y por ultimo el método ModificarDatos() que se conecta con la base de datos, se utilizara este string: String Modificar="CALL ModificarDatos(?,?,?,?,?)"; para invocar al procedimiento almacenado ModificarDatos y se prepara la sentencia CallableStatement  para envíar los datos necesarios al procedimiento y modificar el registro correspondiente de la tabla empleados, al final refrescara el JTable con los nuevos datos de la tabla empleado.

public String ModificarDatos(int codigo, String nombres, String cargo, String dpto, String jefe){
           Connection cnn;
           String resultado;
        try{
           cnn=Conexion.Conectar();
           CallableStatement cmst= cnn.prepareCall(Modificar);
           cmst.setInt(1,codigo);
           cmst.setString(2,nombres);
           cmst.setString(3,cargo);
           cmst.setString(4, dpto);
           cmst.setString(5, jefe);
           cmst.execute();            
           resultado="Los datos se modificaron correctamente !!!";
           cnn.close();
        }catch(SQLException sqlex){System.out.println(sqlex.getMessage());
           resultado="No se realizo la operacion" +sqlex.getMessage();
        }catch(Exception ex){System.out.println(ex.getMessage());
           resultado="No se realizo la operacion" +ex.getMessage();
        }return resultado;
    }

Eliminar datos de la tabla empleado(Package Formulario)
Primero mostrare el procedimiento almacenado en MySQL para eliminar datos en la tabla empleado

DELIMITER $$
USE `registro`$$
DROP PROCEDURE IF EXISTS `BorrarDatos`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `BorrarDatos`(IN CodigoB INT)
    READS SQL DATA
BEGIN  
    DECLARE error INT;
START TRANSACTION;
DELETE FROM empleado WHERE Codigo=CodigoB;
SET error=(SELECT @error);
IF(error=0) THEN
ROLLBACK;
ELSE
COMMIT;
END IF;    
    
    END$$

DELIMITER ;

Ahora el evento click del botón Eliminar Datos, este invoca al método EliminarDatos() y le envía los parámetros necesarios para realizar la operación de eliminar un registro de la tabla empleado

private void BEliminarActionPerformed(java.awt.event.ActionEvent evt) {
       String resultado;
        int codigo=Integer.parseInt(txtCodigo.getText());
       resultado=EliminarDatos(codigo);
       setTitle(resultado);
       CargarDatos();
    }

y por ultimo el método EliminarDatos() que se conecta con la base de datos, se utilizara este string: String Eliminar="CALL BorrarDatos(?)"; para invocar al procedimiento almacenado BorrarDatos y se prepara la sentencia CallableStatement   para envían los datos necesarios al procedimiento y eliminar el registro correspondiente de la tabla empleados, al final refrescara el JTable con los nuevos datos de la tabla empleado.
public String EliminarDatos(int codigo){
          Connection cnn;
          String resultado;
      try{
        cnn=Conexion.Conectar();
        CallableStatement cmst=cnn.prepareCall(Eliminar);
        cmst.setInt(1, codigo);
        cmst.execute();
        resultado="Los datos se eliminaron correctamente !!!";
        cnn.close();
      }catch(SQLException sqlex){System.out.println(sqlex.getMessage());
        resultado="No se realizo la operacion" +sqlex.getMessage();
      }catch(Exception ex){System.out.println(ex.getMessage());
        resultado="No se realizo la operacion" +ex.getMessage();
      }return resultado;
    }
Main de la aplicación y variables del formulario(Package Formulario)
El Main del formulario y las variables de este se muestra a continuación:
public static void main(String args[]) {
    
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Java_MySQL().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify                     
    private javax.swing.JButton BCerrar;
    private javax.swing.JButton BEliminar;
    private javax.swing.JButton BIngresar;
    private javax.swing.JButton BLimpiar;
    private javax.swing.JButton BModificar;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable tablita;
    private javax.swing.JTextField txtCargo;
    private javax.swing.JTextField txtCodigo;
    private javax.swing.JTextField txtDepartamento;
    private javax.swing.JTextField txtJefe;
    private javax.swing.JTextField txtNombres;
    // End of variables declaration                   
}