martes, 27 de septiembre de 2016

Columnas virtuales con MySQL

Las columnas virtuales son una de las características más resaltantes de MySQL 5.7. Estas columnas tienen la característica de ser definidas en la tabla como el resultado de funciones de otras columnas, por ejemplo:
create database demo;
use demo;
create table tabla(campo1 int, campo2 int, campo3 int generated always as (campo1*campo2) virtual);
insert into tabla values (10, 20, default);
select * from tabla;
+--------+--------+--------+
| campo1 | campo2 | campo3 |
+--------+--------+--------+
|     10 |     20 |    200 |
+--------+--------+--------+

La tabla creada con estas sentencias SQL tendrá dos columnas que almacenarán números enteros y una tercera columna que será el resultado de la multiplicación de las dos columnas anteriores, tal como se muestra en la siguiente figura:


Dichas columnas virtuales son cálculadas sobre la marcha, cada vez que los campos son recuperados. Una de las limitantes es que no podemos utilizar columnas virtuales definidas después de la actual, esto debido a que las columnas virtuales se calculan en el orden en que se definen.

Existe otro tipo de columnas generadas, llamadas columnas almancenadas, pero éstas serán revisadas en otro artículo.

lunes, 19 de septiembre de 2016

Secure Admin must be enabled to access the DAS remotely

En este corto artículo les presento la solución al error:

Secure Admin must be enabled to access the DAS remotely

Que ocurre cuando queremos acceder remotamente a un servidor glassfish recientemente instalado. La solución es tan sencilla como ejecutar el siguiente comando:

asadmin --host [host] --port [port] enable-secure-admin


Recuerden reiniciar el servicio para que los cambios tomen efecto. Saludos!

martes, 13 de septiembre de 2016

How to Install and Configure MySQL Cluster on Windows

MySQL Clúster es una versión de alta disponibilidad, alta redundancia de MySQL adaptada para el entorno de computación distribuida. Usa el motor de almacenamiento NDB Cluster para permitir la ejecución de varios servidores MySQL en un clúster. Este motor de almacenamiento está disponible en las distribuciones binarias de MySQL 5.0, Los sistemas en los que está disponible son Linux, Solaris y Windows. En este artículo vamos a revisar la manera cómo configurarlo.

La infraestructura que utilizaremos será la siguiente:


Los requerimientos son los siguientes:


Las recomendaciones son estas:

  • Desactivar firewall
  • Desactivar antivirus
  • Desinstalar y limpiar versiones anteriores de MySQL

Una vez descargada la versión, descomprimir el contenido en una carpeta en el disco C, a la cual llamaremos mysqlc.

En cada uno de los tres nodos de la figura mostrada anteriormente, crear la estructura de carpetas y su contenido a partir del comando:
C:\>mkdir my_cluster my_cluster\ndb_data my_cluster\mysqld_data my_cluster\conf
C:\>mkdir my_cluster\mysqld_data\mysql my_cluster\mysqld_data\ndbinfo
C:\>copy c:\mysqlc\data\mysql my_cluster\mysqld_data\mysql 
C:\>copy c:\mysqlc\data\ndbinfo my_cluster\mysqld_data\ndbinfo

Nodo Administrador
Crear el archivo config.ini en la carpeta c:\my_cluster\conf con el siguiente contenido:
[ndb_mgmd]
HostName=192.168.1.100
DataDir=c:\my_cluster\ndb_data
Nodeid=1

[Ndbd default]
NoOfReplicas=2

[Ndbd]
HostName=192.168.1.101
Nodeid=3

[Ndbd]
HostName=192.168.1.102
Nodeid=4
[Mysqld]
[Mysqld]
Iniciar el nodo administrador ejecutando el siguiente comando y dejando la consola abierta.
C:\my_cluster>/mysqlc/bin/ndb_mgmd -f conf/config.ini --initial --configdir=c:\my_cluster\conf\
En otra consola de comandos del nodo administrador, ejecutar el programa para verificar el estado de nuestro cluster.
C:\>C:\mysqlc\bin\ndb_mgm -e show
El resultado deberá ser similar al mostrado a continuación:


Nodos de Datos
En cada uno de los nodos de datos, crear el archivo my.cnf en la carpeta c:\my_cluster\conf. El puerto debe ser diferente para cada nodo de dato y de preferencia mayor a 5000.
[mysqld]
ndbcluster
datadir=c:\my_cluster\mysqld_data
port=15002
ndb-connectstring = 192.168.1.100

[mysql_cluster]
ndb-connectstring = 192.168.1.100
Ahora nos conectamos con el nodo administrador ejecutando el siguiente comando en cada uno de los dos nodos de datos
C:\>c:\mysqlc\bin\ndbd -c 192.168.1.100:1186
Sin embargo, al ejecutar en el nodo administrador el siguiente comando.
C:\>C:\mysqlc\bin\ndb_mgm -e show
Podemos notar que, a pesar que la conexión al nodo administrador ha sido hecha, los nodos SQL aún no están habilitados (not connected, accepting connect from any host).


Para levantar las API's, ejecutar en cada nodo de datos el siguiente comando en una consola nueva:
C:\my_cluster>c:\mysqlc\bin\mysqld --defaults-file=conf/my.cnf --console
Al volver a ejecutar el comando de visualización de conexiones en el nodo administrador, la salida será la siguiente:


Ahora sólo resta conectarnos al motor de base de datos de cada nodo utilizando una nueva consola para ejecutar el siguiente comando, teniendo en cuenta el puerto establecido en el archivo my.cnf. En este caso, mostraremos la conexión en el nodo que utiliza el puerto 15002.
c:\my_cluster>c:\mysqlc\bin\mysql -P15002 -u root
Al levantar los dos motores, cualquier sentencia SQL ejecuta en uno de ellos deberá verse automáticamente reflejada en la otra instancia. La siguiente imagen ilustra esto:


Inicialmente, en la consola azul habían las mismas base de datos que en la consola blanca, sin embargo al crear la base de datos clusterdb en esta última, la instancia azul reflejó automáticamente los cambios.

Para finalizar, les dejo los comandos para finalizar el servicio de manera segura:
#Ejecutar por cada nodo de datos, teniendo en cuenta el puerto
C:\my_cluster>c:\mysqlc\bin\mysqladmin -u root -h 127.0.0.1 -P15000 shutdown
#Nodo administrador
C:\my_cluster>c:\mysqlc\bin\ndb_mgm -e shutdown
#Ver puertos
netstat -oan

lunes, 12 de septiembre de 2016

How to use Java 8 predicate

Las expresiones lambda son funciones anónimas, es decir que no necesitan una clase. Su sintaxis básica se muestra a continuación:

parámetros → {Cuerpo lambda}

En caso de que el cuerpo lambda presenta más de una línea de código, será necesario incluir las llaves. En caso devuelva un valor, será necesario incluir también la cláusula return.

A continuación, mostraré algunos ejemplos del uso de predicados utilizando funciones lambda. Recuerden que estas características sólo están disponibles en la versión 8 del JDK.

Predicado simple
Representa una función con un único argumento cuyo valor de retorno será de tipo booleano. Aplicaremos este caso para verificar si un número es primo o no.

import java.util.function.Predicate;
import java.util.stream.IntStream;

/**
 *
 * @author Rolando
 */
public class Main {

    public static void main(String[] args) {
        System.out.println(isPrimo(1));
        System.out.println(isPrimo(2));
        System.out.println(isPrimo(3));
        System.out.println(isPrimo(4));
    }

    private static boolean isPrimo(final int numero) {
        Predicate<Integer> isDivisible = divisor -> numero % divisor == 0;
        return numero > 1 && IntStream.range(2, numero).
                noneMatch(index -> isDivisible.test(index));
    }
}

Encadenamiento de predicados
Los predicados también puede ser encadenados entre sí utilizando conectores de tipo AND, OR y de negación como si de cualquier expresión lógica se tratase. A continuación, se muestra un ejemplo sencillo en donde se verifica, a través de dos predicados, que un número se encuentra en un rango determinado.
import java.util.function.Predicate;

/**
 *
 * @author Rolando
 */
public class Main {

    public static void main(String[] args) {
        System.out.println(isInRange(7, 2, 8));
        System.out.println(isInRange(9, 11, 15));
    }

    private static boolean isInRange(final int numero, final int limiteInferior, final int limiteSuperior) {
        Predicate<Integer> mayorNumero = i -> i >= limiteInferior;
        Predicate<Integer> menorNumero = i -> i <= limiteSuperior;
        return limiteSuperior >= limiteInferior && mayorNumero.and(menorNumero).test(numero);
    }
}

Predicados como argumentos de funciones
Java 8 también nos permite pasar predicados como argumentos de funciones. En el siguiente ejemplo, sólo vamos a permitir números que cumplan con la regla que es establecida como parámetro de la función procesar.
import java.util.function.Predicate;

/**
 *
 * @author Rolando
 */
public class Main {

    public static void main(String[] args) {
        procesar(11, (i) -> i > 10);
        procesar(9, (i) -> i % 3 == 0);
    }

    /**
     * Función que recibe un predicado como parámetro
     *
     * @param number
     * @param predicate
     */
    static void procesar(int number, Predicate<Integer> predicate) {
        if (predicate.test(number)) {
            System.out.println("Número " + number + " ha sido aceptado!");
        }
    }
}

También podemos filtrar elementos de una lista utilizando predicados. El siguiente ejemplo lo ilutra:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
 *
 * @author Rolando
 */
public class Main {

    public static void main(String[] args) {
        List<Usuario> users = new ArrayList<>();
        users.add(new Usuario("John", "admin"));
        users.add(new Usuario("Peter", "member"));
        List<Usuario> lstAdministradores = process(users, (u) -> u.getUsuario().equals("admin"));
        System.out.println(lstAdministradores.size());
    }

    static List<Usuario> process(List<Usuario> users, Predicate<Usuario> predicate) {
        List<Usuario> result = new ArrayList<>();
        for (Usuario user : users) {
            if (predicate.test(user)) {
                result.add(user);
            }
        }
        return result;
    }
}

class Usuario {

    private String nombre;
    private String usuario;

    public Usuario(String nombre, String usuario) {
        this.nombre = nombre;
        this.usuario = usuario;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getUsuario() {
        return usuario;
    }

    public void setUsuario(String usuario) {
        this.usuario = usuario;
    }
}