Transaction marked as rollbackOnly

Senhores,

considerando o modelo de classes em anexo, tenho uma página de inclusão do cliente. Lá o usuário tem a chance de “validar” um logradouro que ela escrever. Quando ele o faz, o banco de dados prepara o formulário preenchendo o endereço já existente se só existir um logradouro de acordo com o que foi procurado ou exibe uma lista caso contrário.

A questão é que, se o logradouro não está pré-cadastrado o usuário define o novo endereço na mesma página e as regras do negócio resolvem o problema. Mas se por acaso é digitado um bairro, logradouro ou cidade inexistente, estes também são inserido automaticamente.

Este é o código do JPA que trata a coisa:

[code] @Transactional(readOnly=false)
public void salvar(Cliente cliente){
RegiaoEndereco reCliente = cliente.getEndereco().getRegiaoEndereco();
TipoEndereco t = null;
t = bU.buscarTipoEndereco(reCliente.getTipoEndereco().getId());

	Logradouro l = null;
	try {
		l = bU.buscarLogradouroExato(reCliente.getLogradouro().getNome());
		em.merge(l);
	} catch (NoResultException n){
		l = new Logradouro();
		l.setNome(reCliente.getLogradouro().getNome());
		em.persist(l);
	}
	
	Bairro b = null;
	try {
		b = bU.buscarBairroExato(reCliente.getBairro().getNome());
		em.merge(b);
	} catch (NoResultException n){
		b = new Bairro();
		b.setNome(reCliente.getBairro().getNome());
		em.persist(b);
	}
	
	Cidade cid;
	try {
		cid = bU.buscarCidadeExato(reCliente.getCidade().getNome());
		em.merge(cid);
	} catch (NoResultException n){
		cid = new Cidade();
		cid.setNome(reCliente.getCidade().getNome());
		em.persist(cid);
	}

	// Desnecessário procurar estado, enquanto o software não sair do RJ (Eh, eh!).
	Estado e = bU.buscarEstadoExato("RIO DE JANEIRO");
	em.merge(e);
	RegiaoEndereco re = new RegiaoEndereco(t, l, b, cid, e);

	RegiaoEndereco reReal = null;
	try {
		reReal = bU.buscarRegioesEnderecosExato(re);
		em.merge(reReal);
	} catch (NoResultException n){
		reReal = re;
		em.persist(reReal);
	}

	cliente.getEndereco().setRegiaoEndereco(reReal);
	if (cliente.getId() == null){
		em.persist(cliente);
	} else {
		em.merge(cliente);
	}
}

[/code]

Como uso o Struts2, uso a função de preenchimento de todo o gráfico do objeto. Por isso verifico se o logradouro, bairro e cidade já existem para incluí-los ou não.

Pois bem, depois de me alongar desse jeito, quando preciso incluir um dos valores (bairro, cidade, etc.) no código, é disparado o erro abaixo:

SEVERE: Servlet.service() for servlet default threw exception javax.persistence.RollbackException: Transaction marked as rollbackOnly at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:51) at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:456) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:709) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:678) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) at $Proxy24.salvar(Unknown Source) at br.com.pizzaria.servico.ClientesServico.salvar(ClientesServico.java:32) at br.com.pizzaria.acoes.ClientesCRUDAction.salvar(ClientesCRUDAction.java:40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source)

Todo este gráfico está marcado com o CascadeType.ALL. Eu sei que o setRollbackOnly é disparado somente quando uma exceção não-checada é lançada. Mas no log não aparece nada! Existe alguma outra possibilidade da transação ser marcada para rollBackOnly()?

Alguém tem alguma pista?

Muito obrigado pela paciência e desculpem pelo testamento. Estou no desespero e não queria mudar muito a linha de raciocínio.

Galera, me ajuda aí!

 Valeu.