Spring – Utilizar un pool de conexiones y una clase auxiliar para la ejecución de SQL

La mayoría de aplicaciones requieren acceso a una base de datos. En java existe JDBC que nos permite realizar esta tarea.
En una aplicación distribuida y escalable nos vemos en la necesidad de utilizar un pool de conexiones para no causar un problema de rendimiento. Por ejemplo, he creado servicios web (REST) que deseo sean consumidos desde dispositivos móviles, para ello necesito que los servicios sean escalables.

Ya que utilicé Spring Roo para crear la plantilla inicial del proyecto, este me agregó la siguiente configuración inicial.

applicationContext.xml

...
    <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
        <property name="driverClassName" value="${database.driverClassName}"/>
        <property name="url" value="${database.url}"/>
        <!--<property name="username" value="${database.username}"/>-->
        <!--<property name="password" value="${database.password}"/>-->
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="true"/>
        <property name="testWhileIdle" value="true"/>
        <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
        <property name="numTestsPerEvictionRun" value="3"/>
        <property name="minEvictableIdleTimeMillis" value="1800000"/>
        <property name="validationQuery" value="SELECT 1 FROM DUAL"/>
    </bean>
...

como podemos ver, esta configuración crea un DataSource de tipo org.apache.commons.dbcp.BasicDataSource. Este tipo de DataSource crea un pool de conexiones automáticamente. Genial!

Ahora, ¿cómo lo utilizamos en nuestras clases para poder ejecutar una consulta SQL?

Podríamos utilizarlo de la forma tradicional con JDBC

...
    @Autowired
    public DistritosServiceImpl(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public List<Distrito> getDistritos() {
        List<Distrito> distritos = new ArrayList<Distrito>();
        String sql = 
                "select id, nombre " +
                        "from distritos";
        Connection con = null;
        try{
            con = this.dataSource.getConnection();
            PreparedStatement stmt = con.prepareStatement(sql);
            ResultSet rs = stmt.executeQuery();
            while(rs.next()){
                distritos.add(new Distrito(rs.getInt("id"), rs.getString("nombre")));
            }
        }catch (Exception e){
            e.printStackTrace();
            if(con != null){
                try {
                    con.close();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
        }
        return distritos;
    }
...

pero existe una mejor manera, utilizando JdbcTemplate

...
    @Autowired
    public DistritosServiceImpl(DataSource dataSource) {
        this.dataSource = dataSource;
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Override
    public List<Distrito> getDistritos() {
        String sql =
                "select id, nombre " +
                        "from distritos";
        return jdbcTemplate.query(sql, new RowMapper<Distrito>() {
            @Override
            public Distrito mapRow(ResultSet rs, int i) throws SQLException {
                return new Distrito(rs.getInt("id"), rs.getString("nombre"));
            }
        });
    }
...

Fuentes:

ORA-06550: número o tipos de argumentos erróenos

Recientemente tuve que desempolvar un proyecto de .NET (C#) y hacer unas modificaciones.
Había que utilizar las clases de System.Data.Oracle en vez de Oracle.DataAccess debido a que, la segunda, ocasionaba un timeout de conexión con la versión 11.2 de Oracle Database Server.

Una vez que sustituí las clases y corregí todos los errores de compilación ocasionados por el cambio, ejecute la aplicación para probar su funcionalidad. Para mi sorpresa me lanzó la siguiente excepción:

ORA-06550: línea 1, columna 7: PLS-00306: número o tipos de argumentos erróenos al llamar a ‘PR_GETEXPEDIENTESXFACUERDO’
ORA-06550: línea 1, columna 7: PL/SQL: Statement ignored

Verifiqué muchas veces que el número o tipo de los parámetros fuera el correcto, pero seguía sin funcionar. En un acto de desesperación sustituí la llamada al procedimiento por una consulta sql estándar, pero no tuve éxito. Ya sin más ideas noté que el nombre de los parámetros en el código era distinto a los nombres en el procedimiento almacenado. Intenté renombrarlos, ya sin nada que perder, y asombrosamente funcionó. Al parecer la clase OracleCommand de System.Data.Oracle toma en cuenta el nombre de los parámetros mientras que la de Oracle.DataAccess no.

Fuentes:
https://community.oracle.com/thread/2171363?start=0&tstart=0
http://support.microsoft.com/kb/322160
http://blogs.msdn.com/b/spike/archive/2009/06/16/oracle-stored-procedures-with-ref-cursor-from-net-code-and-bid-tracing.aspx

Java – Ambiente de producción y desarrollo

Lo más común es desarrolllar nuestras aplicaciones en un ambiente de desarrollo, es decir, utilizar servidores de prueba para después implementarlo en un ambiente de produción. Si el código de tu proyecto se encuentra en un sistema de control de código (git, svn, etc.) es díficil, si no tedioso, cambiar entre un ambiente y otro. Tienes que modificar los archivos de configuración para que se conecte a la base de datos de producción cada vez que actualizas el sistema y debes tener cuidado de no incluir en el control de código las conexiones de prueba o visceversa.

Para resolver este problema podemos utilizar JNDI, pero se vuelve complicado el mantener un entorno replicado en nuestra máquina de desarrollador. Eixsten plataformas para desarrollar y ejecutar aplicaciones web de forma escalable -tales como- Heroku, Google App Engine o Microsoft Azure. Para resolver este problema de contextos, Heroku ha optado por utilizar variables de ambiente para cambiar entre el contexto de desarrollo y el de producción.

Esta solución me pareció adecuada y decidí implementarla en un proyecto Java. Realmente es muy sencillo, normalmente creamos una conexión a la base de datos de la siguiente forma:

DriverManager.getConnection(dbUrl, dbUser,dbPassword);

Necesitamos 3 cosas: url a la base de datos, usuario y contraseña.
Opcionalmente podemos incluir el usuario y contraseña en la URL de la base de datos si el controlador lo permite.En el caso de Oracle es de la siguiente manera:

jdbc:oracle:thin:[USER/PASSWORD]@[HOST][:PORT]:SID
jdbc:oracle:thin:[USER/PASSWORD]@//[HOST][:PORT]/SERVICE

Para leer la configuración de las variables de ambiente sería

DriverManager.getConnection(System.getenv(«DATABASE_URL»));

En nuestro caso utilizamos diferentes conexiones de acuerdo al usuario y la base de datos, por lo que seguimos una nomenclatura de la siguiente manera

USUARIO_AT_DATABASE

así por ejemplo, podríamos conectarnos a distintas bases de datos

   DriverManager.getConnection(System.getenv("RH_AT_QUERETARO"));
   DriverManager.getConnection(System.getenv("RH_AT_AMEALCO"));
   DriverManager.getConnection(System.getenv("USRCIVQRO_AT_QUERETARO"));

Por último necesitas configurar estas variables de ambiente en tu sistema operativo.

En Ubuntu lo puedes hacer de diferentes formas.
A mi me funcionó creando un archivo env.sh en la carpeta /etc/profile.d

   #!/usr/bin/bash
   export RH_AT_CENTRO_DE_JUSTICIA=jdbc:oracle:thin:rh/secret@127.0.0.1:1521:dbtest
   export COMPRAS_AT_AMEALCO=jdbc:oracle:thin:compras/secret@127.0.0.1:1521:dbtest

Fuentes:
https://devcenter.heroku.com/articles/heroku-postgresql#connecting-in-java
http://stackoverflow.com/questions/5547224/username-password-in-jdbc-connection-url
https://help.ubuntu.com/community/EnvironmentVariables
http://askubuntu.com/questions/307023/command-not-working-in-profile

SQLDeveloper – Trabajar con MySQL

Habia escuchado que sqldeveloper te deja trabajar con MySQL pero nunca lo habia intentado. Decidi probarlo el dia de hoy y no fue tan facil como pense.

Primero crei que mediante las actualizaciones iba a poder instalar el soporte para MySQL asi que di clic en el menu Help->Check for Updates… y seleccione los 3 centros de actualizacion: Oracle SQL Developer, Oracle Extensions y Third Party SQL Developer Extensions. Despues busque «mysql» y me aparecio casi inmediatamente «MySQL JDBC Driver 11.1.1.58.17» en los resultados asi que segui el asistente esperando que todo quedara listo para crear una conexion a MySQL. Me pidio que aceptara la licencia del controlador y que ingresara mis datos de OTN para desargar los archivos necesarios. No me marco ningun error y me pidio que reiniciara la aplicacion. Una vez hecho esto quise crear mi conexion pero ups!… no aparecia ninguna opcion de MySQL en el asistente de conexion. Lo intente varias veces sin obtener resultados positivos.

Asi que buscando en internet encontre este sitio donde se explica como descargar e instalar manualmente el controlador JDBC de MySQL.

En resumen, descarga y descomprime el archivo Connector/J de esta pagina y ve a las preferencias de SQLDeveloper (Tools->Preferences) en la seccion de Database->Third Party JDBC Drivers, da clic en Add Entry y selecciona el archivo mysql-connector-java-5.1.13-bin.jar de la carpeta que descomprimiste. Listo, ya tendras disponible una pestaña de MySQL a la hora de crear una nueva conexion.

Pentaho – Compartir la Conexión a la Base de Datos

https://i0.wp.com/farm1.static.flickr.com/57/162612973_5e3eeacdbe.jpg
Para importar los datos de unas tablas de Visual Fox Pro a Oracle utilizo Pentaho Data Integration ,tambien conocido como Kettle o Spoon.
Para relizar esta tarea he creado un «trabajo (job)» para controlar el orden de ejecución y varias «transformaciones (transformations)» para copiar los datos. Para no tener que configurar las mismas conexiones en cada transformación, busqué la forma de compartir una conexión. Afortunadamente Keetle nos permite hacer esto de una forma muy sencilla, solo tienes que dar clic derecho sobre la conexion que deseas compartir y dar clic en «Share» -esto guardará la información de la conexión en el archivo «~/.kettle/shared.xml» y te permitirá usar la conexión en otras transformaciones-
Si ya tenías abierta la transformación donde quieres utilizar la conexión, cierrala y abrela nuevamente para que se actualice la lista de conexiones.

Oracle – JDBC URL para un RAC

Cuando tienes un RAC de Oracle y deseas conectarte mediante JDBC (ya sea desde SQL Developer, Pentaho Data Integration o desde tus programas escritos en Java) la URL de JDBC que debes usar para conectarte sería como la siguiente:

jdbc:oracle:thin:@ (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.1)(PORT = 1521))
    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.2)(PORT = 1521))
    (LOAD_BALANCE = yes)
    (CONNECT_DATA =
      (SERVER = SHARED)
      (SERVICE_NAME = dbtest.mydomain.com)
      (FAILOVER_MODE =
    (TYPE = SELECT)
    (METHOD = BASIC)
    (RETRIES = 180)
    (DELAY    = 5)
      )
    )
  )

Oracle – JDBC URL

La URL le indica a JDBC el controlador que va a utilizar y la base de datos a la que se va a conectar. Tambien puede incluir el usuario y contraseña. La forma general es la siguiente:

jdbc:oracle:<drivertype>:<username/password>@<database>

donde <database> es de la forma:

  • //<host>:<port>/<service>
  • <host>:<port>:<SID>
  • <TNSName>

un ejemplo seria:

jdbc:oracle:thin:@192.168.0.1:1521:dbtest

donde vamos a utilizar el controlador «jdbc:oracle:thin» y no especificamos usuario ni contraseña, la base de datos a la que nos conectamos esta en la ip 192.168.0.1 en el puerto 1521 (default) y el SID de la base es «dbtest».

Fuentes:
Oracle JDBC FAQ