Error de Oracle ORA-12705 (Cannot access NLS data files or invalid environment specified)

Hay veces que al conectarnos a una base Oracle, nos retorna un error ORA-12705 con el mensaje “ORA-12705:Cannot access NLS data files or invalid environment specified”, o en un ambiente en español “ORA-12705: No se puede acceder a los archivos de datos NLS o se ha especificado un entorno no válido”.

Un stack trace típico de este error en una aplicación Java es algo parecido a esto:

Caused by: java.sql.SQLException: ORA-00604: error occurred at recursive SQL level 1
ORA-12705: Cannot access NLS data files or invalid environment specified
	at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:283)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:278)
	at oracle.jdbc.driver.T4CTTIoauthenticate.receiveOauth(T4CTTIoauthenticate.java:785)
	at oracle.jdbc.driver.
T4CConnection.logon(T4CConnection.java:362)
	at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:414)
	at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:165)
	at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:35)
	at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:801)
	at java.sql.DriverManager.getConnection(DriverManager.java:582)
	at java.sql.DriverManager.getConnection(DriverManager.java:185)
	at org.apache.commons.dbcp.DriverManagerConnectionFactory.createConnection(DriverManagerConnectionFactory.java:65)
	at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:294)
	at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:840)
	at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:96)
	... 7 more

O algo parecido a esto, en español:

ORA-12705: No se puede acceder a los archivos de datos NLS o se ha especificado un entorno no válido); nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (ORA-00604: se ha producido un error a nivel 1 de SQL recursivo ORA-12705: No se puede acceder a los archivos de datos NLS o se ha especificado un entorno no válido)

En mi caso, el problema se da cuando tengo el sistema operativo -y el conjunto de caracteres- configurado para Uruguay. Para solucionarlo en las aplicaciones Java, podemos agregar opciones para configurar el locale que queremos que la JVM utilice, de forma que no tome el del sistema operativo. Esto se hace agregando las siguientes opciones al ejecutar el comando java:

-Duser.region=us -Duser.language=en

Con user.region configurada para ‘us’ y user.language para ‘en’ no falla, eso es seguro. La configuración para México (-Duser.region=mx -Duser.language=es) o España (-Duser.region=es -Duser.
language=es) también funciona bien.

Otra opción es setear la variable de entorno NLS_LANG con un valor de tres partes: _.. Ejemplos de NLS_LANG pueden ser “AMERICAN_AMERICA.WE8ISO8859P1″ o “AMERICAN_AMERICA.UTF8″. Podemos ver todos los valores válidos para el lenguaje, territorio y conjunto de caracteres en la vista llamada V$NLS_VALID_VALUES, mediante la consulta

SELECT parameter, value FROM V$NLS_VALID_VALUES

Una tercer opción, válida en Windows es cambiar la configuración regional y de idioma para algún país que Oracle soporte (Estados Unidos, España, México, etc.). Hay que tener en cuenta sin embargo que esta configuración nos puede afectar otros programas, especialmente en la configuración de moneda, formato de fecha o de separación de miles.

Los siguientes links tienen buena información al respecto, aunque no muy orientadas a resolver el problema para lenguajes o sets de caractedes “raros” para Oracle:
http://ora-12705.ora-code.com/
http://www.dba-oracle.com/t_nls_lang.htm
http://www.dba-oracle.com/t_ora_12705_error.htm
http://oraclespin.wordpress.com/2008/05/01/setting-nls_lang-for-oracle/

Listado de comandos de administración de Informix

Introducción

La idea de este post es listar algunos comandos útiles para el servidor de base de datos Informix, con el que algunos tenemos que sufrir trabajar día a día. Muchos de ellos se pueden ejecutar desde ambientes gráficos, pero generalmente no disponemos de dichos ambientes en servidores de testing o producción.

Intenteré ir actualizando la lista a medida que me vaya encontrando con otros comandos que considere que valgan la pena.

Los comandos

Bajar el motor

Desde la línea de comandos, ejecutar:

onmode -ky

Podemos hacerlo de forma más “delicada”, siguiendo los siguientes pasos:

Ejecutar

onmode -sy

para dejar no permitir nuevas conexiones, pero permitir que las conexiones que ya estaban abiertas se cierren de forma normal. luego de cerrar todas las conexiones, el servidor queda en quiescent mode, algo
así como inactivo, pero no apagado.

El siguiente paso es movernos al siguiente log lógico, ejecutando:

onmode -l

Luego forzamos un checkpoint, de forma de estar seguros de escribir todos los buffers a disco:

onmode -c

Finalmente, ejecutamos el comando para dejar el servidor de Informix offline:

onmode -ky

Subir el motor

Para subir el motor de Informix, ejecutamos sin parámetros el comando:

oninit

En Linux/UNIX, debemos estar logueados como root o como informix para poder ejecutar oninit. En Windows, se debe ejecutar siendo miembro del grupo Informix-Admin.

Ver la descripción de un error

Dado un código de error, podemos obtener una descripción y posibles acciones correctivas ejecutando:

finderr numero#

El resultado es similar al siguiente (cambiando para cada error, claro está):

infordb:~ # finderr 167
-167    ISAM error: Storage-space size is not multiple of PAGESIZE.

The database server administrator sees this error. When you define a
storage space, you must specify a page size that is an integral multiple of
the system page size. The system page size is set in the Parameters
screen when the database server is first initialized.

Pasar una base de transaccional a no transaccional y viceversa

Al restaurar un respaldo de una base de datos, si no decimos explícitamente, la base restaurada no soportará transacciones, sino que quedará en modo no transaccional. Al intentar utilizarla desde nuestras aplicaciones, las sentencias de BEGIN WORK, COMMIT, ROLLBACK, etc. fallarán por estar trabajando la base en este modo.

En estos casos, podemos pasar la base de datos a transactional unbuffered ejecutando el siguiente comando en una terminal:

ontape -s -L 0 -U [database] 

nO el siguiente, para pasarla a transactional buffered:

ontape -s -L 0 -B [database]

Si por el contrario, queremos pasar una base de modo transaccional a no transaccional, ejecutamos:

ontape -s -L 0 -N [database]

Por información acerca de la diferencia los logging modes transactional unbuffered y transactional buffered, ver este otro post del blog.

Exportar una base de datos

El comando dbexport descarga todos los datos de cada tabla de una base de datos y genera un esquema de la base de datos. Para exportar una base de dato a archivos, debemos ejecutar el siguiente comando en una terminal:

dbexport [database] 

Esto generará un directorio [database].exp con los datos de cada tabla, y desplegará por salida estandar (pantalla,
al menos que se rediriga a un archivo) un script con la creación de los objetos de la base.

Importar una base de datos

Para importar una base de datos podemos ejecutar el comando dbimport. dbimport lee el archivo de esquema generado por el comando dbexport y crea una base de datos cargando los datos de los archivos. Se puede especificar un dbspace determinado, y el logging mode de la base importada:

dbimport [database] [-i directory] [-d dbspace] [-l [buffered]]  

En donde:

  • en [database].exp están ubicados los archivos de datos a importar
  • -d dbspace: especifica el nombre del dbspace en donde la base será creada. Por defecto, será rootdbs.
  • -l: Establece que la base importada funcionará en modo unbuffered transaction logging
  • -l buffered: Establece que la base importada funcionará en modo buffered transaction logging

El parámetro [database] es la ubicación
en de los archivos a importar; el comando buscará un directorio llamado [database].exp para leer los datos de las tablas. Si se especifica, se buscará ese directorio dentro de [directory]. Se asume que existirá un archivo [database].exp/[database].sql conteniendo la estructura de la base de datos (tablas, índices, contraints, etc.).

Mostrar información de uso de espacio físico

Ejecutando el siguiente comando desde una terminal, obtenemos un reporte de los diferentes dbspaces y el espacio utilizado en cada uno:

onstat -d

La salida es similar a la siguiente:

infordb:~ # onstat -d

IBM Informix Dynamic Server Version 10.00.FC7     -- On-Line -- Up 1 days 13:15:39 -- 38720 Kbytes

Dbspaces
address          number   flags      fchunk   nchunks  pgsize   flags    owner    name
450c8e78         1        0x60001    1        1        2048     N  B     Informix rootdbs
45253450         2        0x60001    2        1        2048     N 
 B     Informix datadbs
 2 active, 2047 maximum

Chunks
address          chunk/dbs     offset     size       free       bpages     flags pathname
450c9028         1      1      0          250000     58385                 PO-B  /opt/IBM/Informix/CHUNKS/rootdbs.000
45269db8         2      2      0          1048576    516245                PO-B  /opt/IBM/Informix/CHUNKS/datadbs.000
 2 active, 32766 maximum

NOTE: The values in the "size" and "free" columns for DBspace chunks are
      displayed in terms of "pgsize" of the DBspace to which they belong.

Expanded chunk capacity mode: always

El tamaño y el espacio libre de cada chunk (columnas size y free) están expresadas en páginas. El tamaño de cada página está expresada en bytes en la columna pgsize, por lo que el tamaño de cada chunk está determinado por size x pgsize. Cada chunk está asociado a un dbspace, y esta asociación se detalla en la columna chunk/dbs em> (el primer número es el id del chunk, el segundo es el id del dbspace).

Este reporte también muestra información de replicación, rutas en dispositivos físicos, etc. Por una descripción completa, ver la página de onstat -d en la Administrator’s Reference de Informix.

Actualizar las estadísticas

Desde dbaccess u otro cliente de Informix, podemos ejecutar los siguientes comandos para actualizar las estadísticas de la base de datos:

Actualizar estadísticas de todas las tablas la base de datos:

update statistics

Para actualizar además las estadísticas de distribución de cada tabla (es más lento):

update statistics high	

Para actualizar las estadísticas para una tabla:

UPDATE STATISTICS [HIGH] FOR TABLE [tabla]

Lock mode de las tablas

En este post escribí acerca de los lock modes de Informix. Para obtener la información acerca del tipo de bloqueo que tienen las tablas de una base podemos ejecutar la sigiuente consulta:

SELECT tabname,locklevel FROM systables WHERE tabid>99

La columna tabname contiene el nombre de la tabla, la columna locklevel contiene ‘P’ si el lock mode es por página, o ‘R’ si es por tupla.

Para crear una tabla con un lock mode determinado lo especificamos al ejecutar el comando CREATE TABLE:

CREATE TABLE customer(customer_num serial, lname char(20)...)
LOCK MODE ROW|PAGE|TABLE;

Para cambiar el lock mode de una tabla utilizamos el comando ALTER TABLE:

ALTER TABLE [tabla] MODIFY
LOCK MODE (PAGE|ROW|TABLE)

Referencias

Tagged

Lock modes de tablas de Informix

El lock mode de una tabla especifica el nivel de granularidad que se tendrá para acceder a los datos de forma concurrente. Hay 3 niveles: por tupla (row), por página (page), o por tabla (table).

Al menos que se explicite, al crear una tabla el modo de bloqueo (lock mode) será por página. Si la tabla tiene muchos accesos concurrentes, se puede aumentar la granularidad y usar el modo de bloqueo a nivel de tupla. Este aumento de la granularidad conlleva a un aumento en la cantidad de objetos bloqueados que se deben mantener, lo que redunda en mayor uso de memoria y una posible baja de performance del motor.

Un nivel de bloqueo por tupla sirve cuando se actualizan pocas tuplas de una tabla, o cuando es necesario actualizar de forma concurrente (desde distintas sesiones) distintas tuplas de la misma página. En este caso, si los bloqueos son por página, es posible que las actualizaciones fallen, o tengan que
esperar que se termine de actualizar una tupla de la misma página.

El tipo de bloqueo por tabla utiliza menos recursos que los bloqueos por página o tupla. Este tiplo de bloqueo se pueden utilizar en procesos batch, cuando es un único proceso que accede a cada tabla de la base de datos. De deben tener recaudos con este bloqueos de tablas en sistemas de tipo OLTP. Ante un bloqueo de una tabla, otros procesos de sólo lectura igual podrán acceder a los datos de la misma.

Para obtener la información acerca del tipo de bloqueo que tienen las tablas de una base podemos ejecutar la sigiuente consulta:

SELECT tabname,locklevel FROM systables WHERE tabid>99

La columna tabname contiene el nombre de la tabla, la columna locklevel contiene ‘P’ si el lock mode es por página, o ‘R’ si es por tupla.

Para crear una tabla con un lock mode determinado lo especificamos al ejecutar el comando CREATE TABLE:

CREATE TABLE customer(customer_num serial, lname char(20)...)
LOCK MODE ROW|PAGE|TABLE;

Para cambiar el lock mode de una tabla utilizamos el comando ALTER TABLE:

ALTER TABLE [tabla]
MODIFY LOCK MODE (PAGE|ROW|TABLE)
Tagged

Diferencias entre transactional unbuffered y transactional buffered en Informix

Vale la pena destacar la diferencia entre estos dos modos de trabajo (logging modes) de las bases de datos de Informix.

Informix siempre persiste los datos escribiendo a alguno de sus buffers de log lógico. Si la base de datos en la cual se están haciendo cambios está trabajando en modo unbuffered, estos cambios se escriben al disco duro inmediatamente después de que un registro de commit o rollback llega al log lógico. Si la base de datos está trabajando en modo buffered, el servidor mantiene estos cambios se mantienen en el log el mayor tiempo posible, hasta que ocurre alguno de los siguiente eventos:

  • Un buffer se llena
  • Se ejecuta un checkpoint
  • Se cierra la conexión contra la base de datos
  • Se hace un commit a una base que está trabajando en modo unbuffered

En el modo buffered, existen problemas si el sistema se bloquea antes de
que el buffer de log lógico sea escrito al disco duro pero después de la transacción que el usuario completó ejecutando un commit. La transacción se considerará incompleta y se ejecutará un rollback cuando el motor sea reiniciado y se recupere. En modo unbuffered esto no sucede ya que luego del commit se escribirán los datos de la transacción en el disco duro y no se perderán.

Por defecto, se trabaja en modo unbuffered. Si bien enlententece un poco el motor, es más robusto que el modo buffered frente a caídas del motor en lo que a pérdida de datos respecta.

El tamaño de los buffers de logs lógicos se pueden averiguar en el archivo onconfig (parámetro LOGBUFF).

Referencias:

Tagged

gotAPI: agregador de documentación de diferentes lenguajes y frameworks

gotAPI es un sitio con documentación y APIs de diferentes frameworks y lenguajes. Encontraremos documentación de referencia de Java, Spring framework, Hibernate, diferentes motores de bases de datos, XML y sus relacionados (XSL, XPath, etc.). La documentación sigue creciendo, y como vemos en la captura de pantalla más abajo, al día de hoy esta bastante completa:

gotapi-apis

Yendo a la estructura de la página, tenemos una presentación bien limpia, con un filtro por lenguaje/framework en la parte arriba, y el buscador de texto arriba a la izquierda. El buscador filtra los resultados a medida que escribimos, cosa que resulta muy
conveniente para este tipo de búsquedas. Abajo del buscador tenemos una estructura arbórea de todos los elementos en los que estamos buscando, y en el centro de la página se presenta el resultado.

En su blog hace unos meses anunciaron que estaban trabando en la versión 2.0, y que la beta está disponible para poder probarla. El 16 de junio anunciaron en su twitter que pasarían a producción esta beta, pero esto aún no ha pasado, siguen con la versión vieja.

De todas formas, la versión 2.0 beta está bastante usable, bastante ágil y -al igual que la versión en producción-, con abundante información.

Recomendable cualquiera de las dos.

Manejo transaccional de la base de datos con Spring Framework y AOP

Introducción

Manejar la transaccionabilidad contra una base de datos no es un tema complicado al utilizar JDBC, menos aún utilizando un bean TransactionTemplate de Spring. Sin embargo, siempre que hacemos tareas repetitivas -como escribir código para empezar una trasacción, hacer un commit en caso de éxito o hacer rollback en caso de error- abre la puerta a olvidos o errores de programación.

Spring pone a disposición buenas herramientas para el manejo transaccional contra una base de datos, ya sea de forma programática o de forma declarativa. Si elegimos el enfoque programático, contamos con la clase org.springframework.transaction.support.TransactionTemplate. Si preferimos manejar nuestras transacciones de forma declarativa, contamos con opciones de configuración mediante XMLs y AOP (tx:advice) o utilizando annotations (org.springframework.transaction.annotation.Transactional)
Veremos los diferentes atributos en la definición de una transacción, y las formas de uso de cada uno de los enfoques.

Atributos de una transacción

name

Nombre de la transacción. Por defecto no tienen nombre, y si tienen, este nombre se muestra en los monitores transaccionales, cuando el concepto es aplicable.

propagation

Es el comportamiento de la propagación de la transacción. Por propagación entendemos la forma de asociar la transacción al método que estamos ejecutando. Entre los posibles comportamientos tenemos:

  • REQUIRED: Comportamiento por defecto. Si existe una transacción en curso, el método corre dentro de esa transacción. Si no existe una en curso, creará una nueva transacción.
    tx_prop_required
  • REQUIRES_NEW: Indica que el método debe
    correr dentro de su propia transacción. Si existe una transacción en curso, se suspenderá durante la duración de la invocación al método.
    tx_prop_requires_new
  • MANDATORY: Indica que el método debe correr dentro de una transacción. Si no existe una transacción en curso, se lanzará una excepción.
  • NESTED: Indica que si existe una transacción en progreso, el método se ejecutará dentro de una transacción anidada. Sobre esta transacción se ejecutará commit o rollback sin afectar las otras, (utilizando savepoints) . Si no existe ninguna transacción en curso, se comporta de la misma forma que REQUIRED.
  • NEVER: Indica que el método no debe ser ejecutado utilizando una transacción en curso. Si existe una transacción en curso, se lanzará una
    excepción.
  • NOT_SUPPORTED: Indica que el método no debe ser ejecutado dentro de una transacción. Si existe una en progreso, se suspenderá durante la ejecución del método.
  • SUPPORTS: Indica que el método no requiere una transacción, pero se utilizará si existese alguna en curso.

isolation

El isolation level de la transacción. Por isolation level entendemos la configuración de qué tanto afectan los cambios del DBMS que son externos a nuestra transacción. En el nivel de aislación más bajo vemos cómo van cambiando los datos desde que comenzó nuestra transacción, inclusive si son resultados intermedios de otra transacción. En el nivel más alto, trabajamos con una foto de los datos que no cambia mientras nuestra transacción vive. Entre los posibles valores tenemos:

  • DEFAULT: Utiliza el nivel por defecto, lo determinará la fuente de datos.
  • READ_UNCOMMITED: Este nivel permite que en una transacción se puedan leer datos que aún no han sido commiteados en otras transacciones (lecturas sucias). Pueden suceder además lecturas fantasma (si se hace rollback de la otra transacción, los datos que leímos no fueron válidos) y lecturas no repetibles (una misma consulta puede retornar valores diferentes dentro de la misma transacción).
  • READ_COMMITED: Este nivel no expone datos de una tupla aún no commiteados por otras transacciones, pero permite que otras transacciones cambien datos de las tuplas recuperadas por nuestra transacción. De esta forma, las lecturas sucias se evitan, pero pueden suceder las lecturas fantasma y las lecturas no repetibles.
  • REPEATABLE_READ: Este nivel no permite leer datos aún no commiteados de una tupla, y tampoco permite modificar los datos leídos por una transacción en curso. Sin embargo, si hacemos 2 consultas (SELECTs) con una condición de rango en el WHERE, y otra transacción inserta tuplas entre las 2 consultas y que cumplan con la condición de rango, las consultas retornarán conjuntos de tuplas diferentes. Las lecturas sucias y las lecturas no repetibles se evitan, pero pueden suceder las lecturas fantasma.
  • SERIALIZABLE: Además de las condiciones de REPEATABLE_READ, evita el caso en que en nuestra transacción hacemos una consulta con una condición de rango, otra transacción inserta una tupla que cae cumple la condición, y luego repetimos la consulta en nuestra transacción. Si el es isolation level es SERIALIZABLE, ambas consultas retornarán el mismo resultado. Se evitan las lecturas sucias, las lecturas no repetibles y las lecturas fantasma.

timeout

El timeout de la transacción, expresado en segundos.

read-only

Indica si la transacción debe ser tratada como solo lectura, posibilitando así optimizaciones adicionales.

Uso de transacciones con Spring

Definición de forma programática

Para manejar la transaccionabilidad de forma programática, debemos
tener una referencia a org.springframework.transaction.support.TransactionTemplate en nuestra clase. Para ello, definiremos algunas relaciones entre nuestros beans:

<bean name="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
	<constructor-arg ref="sessionFactory"/>
</bean>

<bean name="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
	<property name="dataSource" ref="dataSource" />
	<property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
	<constructor-arg ref="transactionManager"/>
</bean>

En este ejemplo el framework de ORM utilizado es Hibernate, pero la idea aplica para cualquier framework ORM de los que Spring tiene soporte.
El bean hibernateTemplate entonces es el que agrupa funcionalidades de acceso a datos, apoyándose en las funcionalidades de Hibernate.
El bean transactionManager es una subclase de org.springframework.transaction.support.AbstractPlatformTransactionManager, implementando el manejo de transacciones (determinación de transacciones existentes, suspensión de transacciones, definición del comportamiento transaccional, etc.).
Por último, transactionTemplate simplifica el manejo transaccional y el manejo de excepciones por errores.

La forma de uso del transactionTemplate dentro de nuesta aplicación es la siguiente:

public class MyEntityDAOImpl implements MyEntityDAO {

	private HibernateTemplate hibernateTemplate;
	
	private TransactionTemplate transactionTemplate;	
	
	public List<MyEntity> getAll() {
		return (List<MyEntity>)
getTransactionTemplate().execute(new TransactionCallback() {

			@Override
			public Object doInTransaction(TransactionStatus status) {
				return getHibernateTemplate().loadAll(MyEntity.class);
			}
		});
	}
	
	/*
	...
	setters y getters de hibernateTemplate y transactionTemplate
	...
	*/
}

Todo lo que pase dentro del método doInTransaction estará encapsulado dentro de una transacción.

Definición de forma declarativa – XMLs

El bean nos permite crear un aspecto (por más info acerca de AOP, ver este post) encargado de iniciar una transacción contra la base de datos al invocar un método que encaje en la definición del pointcut. En este pointcut se podría definir para un método de una clase, para toda la clase, o incluso para todo un paquete que identifique la capa de negocios o de acceso a datos de nuestra aplicación.

Para configurar un en nuestra aplicación, incluiremos en nuestros XMLs de Spring los siguientes beans:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

	<aop:config>
		<aop:advisor pointcut="execution(public * demo.dao.*.create(..))" advice-ref="tx-advice" />
	</aop:config>
	
	<tx:advice id="tx-advice">
		<tx:attributes>
			<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Throwable" no-rollback-for="BusinessException" />
			<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
		</tx:attributes>
	</tx:advice>

</beans>

Tendiendo hacia convención en lugar de configuración, asume que existe un bean llamado “transactionManager”, instancia de la clase -en caso de Hibernate- org.springframework.orm.hibernate3.HibernateTransactionManager. Si nuestro transaction manager tiene un nombre diferente, debemos referenciarlo incluyendo un atributo transaction-manager al bean .

El atributo name es el único parámetro requerido, y tiene un significado diferente al que se le da en la configuración programática. En este caso, sirve para filtrar los nombres de los métodos que se asociarán a esta las transacciones. Soporta comodines (*) en los nombres, por ejemplo ‘get*’, ‘handle*’, ‘on*Event’.

Al bean le podemos configurar todos los atributos descritos al inicio del post (propagation, isolation leven, timeout, etc.), y además:

  • rollback-for: Lista de excepciones -separadas por comas- para las cuales se dispara un rollback de la transacción
  • no-rollback-for: Lista de excepciones -separadas por comas- para las cuales no se dispara un rollback de la transacción

Uso de forma declarativa – @Annotations

Si bien simplifica mucho el manejo de transacciones, podemos utilizar annotations para simplificarlo aún más.

Utilizando sólo una línea en la configuración XML de nuestra aplicación podemos dar lugar a configurar el manejo transaccional a nivel de annotations. Esta línea tiene el siguiente formato:

<tx:annotation-driven transaction-manager="txManager" />

El atributo transaction-manager debe ser incluido si nuestro transaction manager no se llama “transactionManager”.

El tener configurado este bean nos habilita a poder anotar nuestras clases y métodos con @Transactional y definir de esta forma nuestras transacciones de forma declarativa y dentro de nuestro código Java.

@Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public class MyServiceImpl implements MyService {
	
	...
	
	@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
	public void addMyEntity(MyEntity e) {
		...
	}
	
	...
}

En este ejemplo, todos los métodos de la clase son anotados como de solo lectura y con el comportamiento de propagación SUPPORTS. Al método addMyEntity se le especifica un comportamiento diferente, anotándolo con el comportamiento de propagación REQUIRED, y eliminando la restricción de solo lectura.

Cabe destacar que @Transactional puede ser utilizado también en interfaces indicando el comportamiento de todas las implementaciones de dicha interface.

Conclusión

Un manejo transaccional apropiado en nuestras aplicaciones es cada día más importante para asegurar robustez, especialmente en ambientes inciertos (desconexiones, latencias) y de alta concurrencia.

Spring nos brinda posiblidades concretas y muy poderosas para aislarnos de la problemática del manejo transaccional, dándonos opciones para las diferentes preferencias de enfoque y opciones en el desarrollo de aplicaciones. Vimos desde cómo hacer para declarar transacciones en el código, teniendo total control acerca del inicio y fin de las mismas. También vimos cómo declarar el ciclo de vida de las transacciones utilizando AOP y Spring juntos, a través de configuración XML. Finalmente vimos aún más simplificada la tarea, habilitando la configuración transaccional mediante annotations, y de esta manera definir en nuestras clases -o interfaces- el comportamiento deseado.

Hoy en día podemos hacer uso de esta flexibilidad y potencia, que quizá hasta hace poco estaba restringida a EJBs, utilizando un framework no intrusivo como Spring, un concepto cada ves más utilizado como AOP y nuestros viejos y queridos POJOs para nuestra lógica.

Referencias

Cheat sheets

En http://www.cheat-sheets.org/ tenemos una colección de hojas de referencia sobre un montón de tecnologías, sistemas operativos, bases de datos, entre otros. Están buenas para tener alguna impresa para pegarle un vistazo si no queremos “googlear” algún detalle particular.

Listo algunas de las más interesantes:

.NET

.NET Format String Quick Referencee
Core C# and .NET Quick Reference by Stephen C. Perry [pdf] (digilife.be)
C# and VB.NET Comparison Cheat Sheet by Steven Swafford [pdf] (aspalliance.com)

CVS

CVS Quick Reference Card Andrew Ford [pdf] (refcards.com)

Design patterns

Design Patterns Quick Reference by Jason S. McDonald [pdf] (mcdonaldland.info)

Eclipse

Eclipse Keyboard Shortcuts by Jesper Kamstrup Linnet [pdf, rtf] (eclipse-tools.sourceforge.net)

FTP

List of FTP commands for the Microsoft command-line FTP client (nsftools.com)

Linux

Unix/Linux Command Cheat Sheet by Jacob [pdf] (fosswire.net)
Linux Administrator’s Quick Reference by Jialong He [pdf] (tiger.la.asu.edu)
The One Page Linux Manual by Squadron [pdf] (homepage.powerup.com.au/~squadron/, digilife.be)

MySQL

MySQL Cheat Sheet by Dave Child [png, pdf] (addedbytes.com)
MySQL cheatsheets by Bob Stein, VisiBone [two wall posters 43cmx61cm or 61cmx87cm, jpg] (visibone.com)
MySQL Cheat Sheet (nparikh.org)
MySQL Database Quick Reference by DeepX [pdf] (tiger.la.asu.edu)

OpenSSH

OpenSSH Configuration Quick Reference by Jialong He [pdf] (tiger.la.asu.edu)

Firefox

Keyboard Shortcuts (mozilla.org)

SQL

SQL in one page (sql.su)
SQL Injection Cheat Sheet (
ferruh.mavituna.com)

SQL Server

SQL Server Cheat Sheet by Dave Child [png, pdf] (addedbytes.com)

Subversion

Subversion Cheat Sheet by Dave Child [pdf] (addedbytes.com)
Subversion Quick Reference Card by Cezary Sobaniec [pdf] (cs.put.poznan.pl)

UNIX

UNIX BASH shell Quick Reference by Arnold Robbins [pdf] (tiger.la.asu.edu)

XML

XML 1.0 Syntax Quick Reference by Mulberry Technologies, Inc. [pdf] (mulberrytech.com)

XPath y XSLT

XSLT 1.0 and XPath 1.0 Quick Reference [pdf] (mulberrytech.com)
XPath by DeepX Ltd [pdf] (refcards.com)

Actualización 24-Nov-2009

Agrego una colección de 25 cheat sheets de diseño web, PHP, WordPress, Photoshop, etc. que me pareció interesante: 34 cheat sheets for web designers and developers