Estoy que lo tiro!!! una nueva entrada sin apenas dejar pasar un par de días para que dijerais la anterior... jajaja...el caso, un día, mis coleguitas del departamento de DataCenter, vamos, los administradores de la base de datos, me vienen a ver (hace un tiempo ya, hará más de un año.....) y me comentan que han de reiniciar los Tomcats de producción cada 2 horas, porque se llena la memoria temporal y no se libera, realmente, lo que querían decir es que YO, estoy llenando la memoria temporal y YO no la libero nunca.... jajajajaja.... se llena, se llena, se llena y nunca se libera..... que ¿qué VOY a hacer para arreglarlo? me preguntan.....
Evidentemente no hace falta que os cuente, que hasta ese día, no tenía n.p.i de que estaba llenando la memoria temporal y por supuesto, de que por ese motivo se estuviesen reiniciando los Tomcats.... jajajajaja.... el caso, les pido tiempo para que me dejen buscar por internet el problema ¿y porqué no? también la solución....viva google!!!!!. Tiempo me dieron, no me puedo quejar, cuando pude ponerme a mirar que pasaba, ya había pasado casi un año.... jajajajajaja (son muy pacientes, las cosas como son....), pero es cierto que no podía ponerme antes con ello, lo juro (soy un programador muy ocupado..... y sólo!!!).
Tengo que deciros que esta vez no he encontrado por internet nada en plan copy/paste, pero sí algunas ayudas, sobre todo la de los compañeros de dataCenter, que me indicaron que en oracle, ellos hicieron la consulta, el problema estaba asociado a --> freeTemporary(); que si era capaz de hacer un freeTemporary() desde java, asunto resuelto...... en un principio, yo no era capaz de hacer ese freeTemporary() desde java, porque se supone que esto lo tenía que hacer IBATIS. Yo trabajo con IBATIS como framework de persistencia contra la base de datos, además, los procesos "gordos" devuelven la información en CLOBs, no puedo trabajar con String porque mis mensajes son enormes y superan en base de datos los 4000 caracteres (no es una limitación de Java, es de base de datos...). IBatis, se supone que debería ayudarme a trabajar con el CLOB, y lo hace, pero tiene/tenía un problema, no liberaba la memoria temporal. ¿qué solución se propone?, una muy sencilla y una muy a mano.... jajajajajaja, crear tu propio manejador de CLOBS. Vale, yo aquí, ya me había hecho caquita encima!!!! ¿como? mi propio manejador? me preguntaba a mi mismo, uffffffffffffff, madre mía!!! esto no lo hago yo en mi vida!!! (esto me lo decía para mis adentros, jamás lo comenté con nadie...jajajajajaja). Pues después de buscar por internet, ver unas 200 páginas webs y 4.500 foros..... lo encontré!!!!!! no, no encontré la solución, pero sí lo que tenía que hacer (ahora lo explico) y como este foro es para compartir este tipo de cosas, no tenía más remedio que publicarlo. Básicamente se trata de "sustituir" lo que hace IBATIS por defecto, por lo que tu le dices a IBATIS que haga, un ejemplo muy sencillo, tu puedes trabajar con boolean, IBATIS siempre devolverá true/false, imagina que a ti te molesta eso y tu quieres que el boolean devuelva 0/1 o verdadero/falso, ¿vale? pues te creas tu propio manejador de boolean y cambias el código para que al devolver true, tu lo cambias por lo que quieras, igual con el false.... no sé si me explico..... para mi ejemplo es "igual", pero en mi caso, no cambio el valor, sino que además de hacer lo que ya hace, además, libero la memoria. Para hacer esto:
En mi ficherito sql-map-config.xml añadimos estas dos líneas (aquí especificamos que para manejar los CLOB lo haga con mi clase....)
<typeAlias alias="OracleDateHandler" type="com.riu.rumbonet.common.
<typeHandler callback="OracleDateHandler" jdbcType="CLOB" javaType="java.lang.String"/>
y la clase que tuve que crear.....
import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
import java.sql.Types;
import oracle.sql.CLOB;
import com.ibatis.sqlmap.client.
import com.ibatis.sqlmap.client.
import com.ibatis.sqlmap.client.
public class ClobTypeHandlerCallback implements TypeHandlerCallback {
public Object getResult(ResultGetter getter) throws SQLException {
CLOB clob = (CLOB) getter.getClob();
Reader reader = null;
StringBuffer result = new StringBuffer(1000);
try {
reader = clob.getCharacterStream();
char[] buffer = new char[clob.getBufferSize()];
int read = 0;
int buffLen = buffer.length;
while((read = reader.read(buffer, 0, buffLen)) > 0 ) {
result.append(buffer, 0, read);
}
clob.freeTemporary();
} catch (IOException e1) {
throw new SQLException("Fallo al leer CLOB: " + e1.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ignore) {}
}
}
return result.toString
}
public void setParameter(ParameterSetter setter, Object parameter) throws SQLException {
String str = parameter.toString();
if (str != null) {
setter.setString(str);
}else{
setter.setNull(Types.CLOB);
}
//System.out.println("
}
public Object valueOf(String s) {
return s;
}
}
Lo más importante es esta función --->clob.freeTemporary();
Para poder ver en base de datos lo que os digo, apuntad esta consulta.
SELECT A.BLOCKS,A.*
FROM V$SORT_USAGE A,V$SESSION B
WHERE B.SADDR =A.SESSION_ADDR
Creo que no me dejo nada, después de subir a producción este cambio y hacer pruebas, ya no hace falta reiniciar los Tomcats en producción. Yuhuuuuuuu!!! un pequeño pasito más en la aplicación!!!! de eso se trata este trabajo, pequeños cambios que significan mucho.
Espero no haberos aburrido, y gracias por estar ahí.
Besos,