miércoles, 19 de febrero de 2014

Deja de concatenar strings con + !!!!

Desde hace años es sabido que concatenar strings con el operador + no es nada recomendable por su bajo rendimiento respecto a otras opciones. Pero la facilidad de su uso ha conseguido que a estas alturas sea la primera opción que usan muchos programadores para juntar varios strings en uno.

Si lo que estás haciendo es un programa tipo "hola mundo" no vas a notar mucha diferencia entre usar el + o no, pero cuando ya te metes en algo más serio puedes estar creando una ralentización de tu código sin saberlo y que tiene muy facil solución: NO USES EL +

La opción con mejor rendimiento es usar StringBuilder y juntar Strings mediante el método append. Pongamos un ejemplo:
String juntaletras = new StringBuilder().append("A").append("BE").append("C").toString();

Como ves tampoco te va a llevar mucho más tiempo hacerlo de esta forma y a la larga vas a salir ganando. La única pega del StringBuilder es que no es synchronized y te puedes llevar un chasco si estás usando programación recurrente multihilos. Para asegurar que tus datos no se corrompen en esos casos puedes usar sin ningún problema StringBuffer. Su uso es similiar a StringBuilder:
String juntaletras = new StringBuffer().append("A").append("BE").append("C").toString();

Cualquiera de las dos opciones mejora el rendimiento del operador + así que ante la duda puedes usar siempre StringBuffer ;)

miércoles, 12 de febrero de 2014

Obtener un array de strings que vienen en un clob

Cada día me sigo sorprendiendo más y más del género humano.
Hoy me he encontrado con la necesidad de obtener un listado de dnis que vienen guardados en un clob para luego tener que recorrerlos para quedarme con los ids a los que corresponden dichos dnis.
La solución más limpia que he encontrado ha sido la siguiente:

DECLARE
  dnis apex_application_global.vc_arr2;

  persona_id number;

BEGIN
  dnis := apex_util.string_to_table(dbms_lob.substr(:NEW.LISTADO,length(:NEW.LISTADO),1), ', ');
  FOR i IN 1..dnis.count LOOP
    SELECT id INTO persona_id FROM persona WHERE dnis(i) = dni;  
  END LOOP;
END;

Cuidado porque si el clob (:NEW.LISTADO) tiene mas de 4000 caracteres va a dar error en la función dbms_lob.substr (que pasa un clob a un varchar2). Como en mi caso se que no va a ser nunca tan grande no me he preocupado pero si no habría que evitarlo (próximamente en sus pantallas...).
Si lo usas dentro de una function o procedure entonces podrías guardar hasta 32767 caracteres en un varchar2.

La gracia del asunto es usar las librerias de apex que metieron en oracle 10, usando por un lado los vectores (apex_application_global.vc_arr2) y por otro lado apex_util.string_to_table que pasa un string a vector indicándole un separador (en mi caso era la ',').

lunes, 10 de febrero de 2014

Configurar timeout de arranque y parada de Tomcat en Eclipse

Se guro que la mayoría de vosotros sabéis montar un Tomcat en Eclipse (es relativamente fácil y puede que me anime a hacer un minitutorial, aunque ya los hay a patadas) así que nos vamos a poner en ese supuesto.
Le dais a correr y ... Ops! error de timeout en la inicialización!!
Al final meterle tantos frameworks, plugins y demás parafernalia al proyecto lo ha convertido en un caballo de guerra que le cuesta bastante arrancar y el tomcat por defecto del eclipse no le da tiempo a montarlo todo en 45 segundos.
No te preocupes porque puedes ir un paso más en la configuración y ajustar dicho valor.
Vas a la vista (view) de servidores (servers) y ahí tendrás tus servidores.
Haz doble click en el nombre del servidor y se abrirá una pantalla con nombre Overview.
Le das a la opción Timeouts y ahí podrás asignar libremente el valor en segundos del timeout de arranque y de parada.
¡Cuando termines no te olvides de guardar!

miércoles, 5 de febrero de 2014

Crear un sequence con el maximo id de una tabla con execute immediate

Seguimos solucionando desaguisados y nos hemos encontrado con una tabla que no tiene ningún sequence para generar ids y se estaban metiendo a pelo.

Como en los distintos entornos (desarrollo, pruebas, producción,...) la tabla en cuestión tiene distinto número de elementos y queremos una solución única para todos los entornos voy a coger el máximo valor del id de la tabla para que la sequence se quede con ese valor para generar el próximo id.
Para ello vamos a usar la función execute immediate dentro de un script que solucionará nuestros problemas.

Primero declaramos una variable integer donde guardar el max id y con una fácil select le añadimos dicho valor. Luego para crear el sequence usamos execute immediate que va a ejecutar lo que le pasemos como parámetro, así que le pasamos el código para crear la secuencia concatenando el valor obtenido antes y asunto solucionado.

Os dejo un ejemplo para que lo disfruteis:

declare
secuencia integer;

begin
select max(id)+1 into secuencia from tabla_sin_sequence;

execute immediate 'CREATE SEQUENCE SEQ_TABLA
MINVALUE 1
MAXVALUE 999999999999999999999999999
INCREMENT BY 1
START WITH ' ||secuencia ||
' NOCACHE
ORDER
CYCLE';

end;
/

lunes, 23 de diciembre de 2013

Obtener el valor de un nodo de un xml en Oracle

Espero por vuestro bien que a nadie se le haya ocurrido guardar un fichero xml con una serie de datos que vayas a necesitar en un blob... pero si a alguno de vuestros compañeros le ha poseido Satán y ha hecho tan atroz fechoría os dejo una forma de obtener dichos datos.

Supongamos que tenemos una tabla_del_demonio con un id y un campo_blob. Para el id 1816 dentro del campo blob guardas un fichero xml de este tipo:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<attributes xmlns="http://www.sat.an/attributes/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:ns3="http://www.sat.an/attributes/trabajadores/1.0">
    <trabajador>
        <nombre>Daniel</nombre>
        <apellido1>Garcia</apellido1>
        <apellido2>Fernandez</apellido2>
        <ns3:dni>123456789B</ns3:dni>
    </specificData>
</attributes>

Para quedarnos con el valor del dni habría que hacer lo siguiente:

select extractvalue(X.XML, '/attributes/trabajador/ns3:dni', 'xmlns="http://www.sat.an/attributes/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:ns3="http://www.sat.an/attributes/trabajadores/1.0"')
from (select XMLType(campo_blob,178) XML
  from tabla_del_demonio
  where id=1816) X;

viernes, 20 de diciembre de 2013

Transformar Clob a Varchar2 en Oracle

Muchas veces te encuentras por misterios de la naturaleza que nadie comprende que en una tabla se está guardando un string de pequeñas dimensiones en un clob.

Si necesitas hacer alguna búsqueda con él, la manera más sencilla es la siguiente:
select * from tabla_misteriosa t where dbms_lob.substr(t.campo_clob,length(t.campo_clob),1) = 'abcdefg';

Si lo que hay dentro del campo_clob tiene un tamaño menor de 4000 caracteres no tendrás ningún problema; pero si es mayor y menor de 32767 caracteres todavía te queda otro camino relativamente facil: usar pl/sql en vez de sql

declare
   ristra varchar2;
begin
   for t in ( select * from tabla_misteriosa )
   loop
       ristra  := dbms_lob.substr( t.campo_clob, length(t.campo_clob), 1 );
       -- Via libre a lo que quieras hacer con ristra

miércoles, 18 de diciembre de 2013

Eclipse ERROR: No generator named “xxx” is defined in the persistence unit

Usando Eclipse con las herramientas de Hibernate te puede salir el error "No generator named “xxx” is defined in the persistence" unit a la hora de usar @GenericGenerator sin que realmente haya dicho error debido a un bug.

Ejemplo:
@Id
@GeneratedValue(generator = “informeGenerator“)
@GenericGenerator(name = “informeGenerator“, strategy = “foreign”, parameters = { @Parameter(name = “property”, value = “informeId”) })
public String getId() {
    return id;
}

En el ejemplo anterior Eclipse te marcará un error en la línea
@GeneratedValue(generator = “informeGenerator“)
indicando No generator named “informeGenerator” is defined in the persistence unit

Actualmente no hay una solución limpia a este bug, pero si quieres que no te moleste puedes desactivarlo desde la opción de menú Preferences -> Java Persistence -> JPA -> Error/Warnings
y marcar Generator is not defined in the persistence unit con Warning.