Spring ORM - Opniões

26 respostas
zorba
bom dia galera :D estou desenvolvendo uma aplicação com spring e alguns de seus modulos, e gostaria de algumas opniões sobre a parte de orm atualmente meu código está assim: applicationContext-hibernate.xml
<?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"
	xsi:schemaLocation="
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">


	<tx:annotation-driven transaction-manager="transactionManager"/>
	
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName">
			<value>org.postgresql.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:postgresql://127.0.0.1:5432/athus</value>
		</property>
		<property name="username">
			<value>postgres</value>
		</property>
		<property name="password">
			<value>adminadmin</value>
		</property>
	</bean>

	<!-- SessioFactory de sessões com o banco! -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
		<property name="configLocation" value="classpath:br/com/athus/hibernate.cfg.xml">
		</property>
	</bean>
	<!-- Fim do bean -->

	<!-- Gerencia as transações com o banco -->
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory">
			<ref local="sessionFactory" />
		</property>
	</bean>
	<!-- Fim do bean -->

	<!-- Aqui vão os DAOs -->
	<bean id="alunoDAO" class="br.com.athus.dao.AlunoDAO">
		<property name="sessionFactory">
			<ref local="sessionFactory" />
		</property>
	</bean>
	
	<bean id="usuarioDAO" class="br.com.athus.dao.UsuarioDAO">
		<property name="sessionFactory">
			<ref local="sessionFactory" />
		</property>
	</bean>

	<!-- Fim dos DAOs -->

	<!-- Carregamento automático do SpringContext ;) Faz o trabalho sujo :D -->
	<bean id="springApplicationContext" class="br.com.athus.util.SpringORMApplicationContextUtils" />

</beans>
GenericDAO
public interface GenericDAO<T> {

	@Transactional
    T create(T newInstance);

    T read(Long id);
    
    List<T> readAll();

    @Transactional
    void delete(Long id);

}
AlunoDAO
public class AlunoDAO extends HibernateDaoSupport implements GenericDAO<Aluno> {

	public Aluno create(Aluno newInstance) {
		try {
			getHibernateTemplate().saveOrUpdate(newInstance);
			return newInstance;
		} catch (DataAccessException e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public Aluno read(Long id) {
		Aluno a = getHibernateTemplate().get(Aluno.class, id);
		return a;
	}

	@Override
	public List<Aluno> readAll() {
		return getHibernateTemplate().loadAll(Aluno.class);
	}

	@Override
	public void delete(Long id) {
		try {
			if(id == null)
				return;
			
			Aluno todelete = getHibernateTemplate().get(Aluno.class, id);
			getHibernateTemplate().delete(todelete);
		} catch (DataAccessException e) {
			e.printStackTrace();
		}
	}

o que vocês acham, o que pode ser melhorado?
sou novo no spring, e não sei se todas as minhas configurações estão corretas. uma delas é o caso das transações. funciona dessa forma?
abraços

26 Respostas

rogelgarcia

GenericDAO é comum utilizar para implementaçoes genéricas de DAO… nao para interface…

Teste o método transacional da seguinte forma (pseudocodigo)

public void metodoTransacional(){ save entity throw exception }

Depois de executar o método verifique se a entidade está persistida… se tiver… a transacao falhou… se nao tiver a transacao está funcionando

zorba

testarei isso, obrigado

zorba
meu dao generico:
@Transactional
    T create(T newInstance) throws Exception;
e minha implementação:
public class AlunoDAO extends HibernateDaoSupport implements GenericDAO<Aluno> {

	public Aluno create(Aluno newInstance) throws Exception {
		getHibernateTemplate().saveOrUpdate(newInstance);
		throw new Exception("");
	}

o aluno foi salvo com sucesso :(

rogelgarcia

Entao… dá uma olhada nas configuracoes aí… pq tem algo nao funcionando…

Só reforçando uma observacao… essa interface nao é um DAOGenerico… é apenas uma interface DAO

zorba

sim, mas qual a diferença. pq eu só tenho a declaração dos metodos comuns a todos os daos, por isso o nome ‘generic’ :smiley: eu sei que não é um dao generico

rogelgarcia

Bem… nao tá errado… mas é interessante seguir o padrao… pq fica mais fácil discutir e visualizar problemas… além de fazer analogias com outros sistemas…

A diferença é o que o GenericDAO é uma classe… que implementa os métodos create, save etc… entao o seu dao de aluno porderia ficar assim

public class AlunoDAO extends GenericDAO<Aluno> { }

Sem nenhum código… pq o código já foi implementado no GenericDAO (GenericDAO é uma classe nesse caso)

Nao tá errado o seu raciocínio… é só uma opniao minha que eu acho que essa sua interface deveria apenas se chamar DAO … e uma implementacao generica é que deveria se chamar GenericDAO

zorba

entendo
você tem razão, pode ser pior pra mim uma hora dessas, se tiver de pedir ajuda e o pessoal se confunde :slight_smile:

rogelgarcia

exato

zorba

descobri que a anotação @Transaction vai emcima da classe, e não no método. agora, a exceção é disparada, mas o aluno ainda é salvo :S

G

Isso porque o rollback só é feito quando é lançada uma runtime-exception.

zorba

hmm, então como eu faria pra testar a transação? pra ver se a minha configuração está correta?

rogelgarcia

Pode ir em cima do método também… talvez é porque tem que ir no método da classe e nao da interface… (isso varia de acordo com a configuraçao … se vc usar proxy based ou cglib based… se nao estou enganado)

Se for isso lançe um RuntimeException()… ao inves de Exception

rogelgarcia

Olhei aqui no spring e realmente tem isso de exceçoes checadas nao dão rollback para conformar com a especificacao EJB3…

Isso pode ser configurável…

Mas teste aí com RuntimeException

zorba

teste com runtime e deu certo, o aluno não foi salvo :smiley:
tive de mudar as exceptions tambem, colocando throws no controlador, e try/catch no managed

G

Rógel, isso não é bem do EJB3, mas sim do JTA. Em ambiente gerenciado qualquer runtime exception e filhas fazem rollback; e o contrário para as checked exceptions. Não sei se o Spring usa JTA por baixo ou se ele apenas simula um JTA, e nesse caso ele faz o mesmo comportamento.

Isso não é configurável não, pelo menos não globalmente. O que pode ser feito é anotar as exceptions com @ApplicationException e configurar o rollback com true ou false. É a única forma e deve ser feito em cada exception. As filhas herdam o mesmo comportamento.

Abaixo uns links que podem ajudar.

http://download.oracle.com/docs/cd/E17477_01/javaee/5/api/javax/ejb/ApplicationException.html
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html

Abraços

rogelgarcia

Eu tinha olhado isso no fonte do Spring… tinha um comentário dizendo que era pra conformar com o EJB3…

Eu disse que era configuravel pois é um objeto que diz se a exceção é tratavel ou nao… se vc trocar esse objeto por um objeto seu… vc pode mudar isso…

Mas na documentaçao do Spring diz… que só é configuravel se usar AOP…

(eu disse que era configuravel… nao que era fácil configurar… ehheheh)

rogelgarcia

Mas fica a pergunta…
O que leva uma pessoa a definir que unchecked-exception dá rollback e checked-exception dá commit…

Ultimamente esse pessoal só tá definindo babela…

G

Rógel, não significa que checked dê commit. A regra do JTA é que se você tem um CMT sempre há um commit, MAS se houver alguma unchecked há rollback.

Checked devem ser tratadas. Então se der um IOException o container não irá fazer rollback porque você deve tratar, e não ir lançando até o ponto mais extremo da sua aplicação.

rogelgarcia

Pois entao… nao é papel do JTA decidir onde eu devo tratar minhas exceções… concorda?

G

Se você usa CMT é responsabilidade dele decidir. Mas se você quer ter um controle melhor pode usar BMT e de posse da UserTransaction fazer commit e rollback onde desejar.

B

Lembrando que CMT é o comportamento default , implícito …

rogelgarcia

Eu entendo como funciona… só nao concordo :smiley:

Pra mim tinha que ser… deu exceçao… faz rollback…

Mas pra que simplificar… se podemos complicar num é verdade ? hehehe

G

Rógel, se você tem uma checked você tem que tratar. Não é questão de complicar não.

O assunto de checked e unchecked é um pouco controverso no Java, e há muitas discuções sobre isso. Não seria diferente para o JTA, já que a transação é baseada em checked e unchecked exceptions.

rogelgarcia

garcia-jj:
Rógel, se você tem uma checked você tem que tratar. Não é questão de complicar não.

O assunto de checked e unchecked é um pouco controverso no Java, e há muitas discuções sobre isso. Não seria diferente para o JTA, já que a transação é baseada em checked e unchecked exceptions.

Concordo… exatamente por essa controvérsia… é que o JTA nao deveria se meter na discussao… heheh

Se vc tem algo controverso… e faz sua API depender de algo controverso… .seu código se tornará controverso…

Agora se vc isola essa controversia… sua app fica limpa…

Acaba que vc tem que programar com ifs na cabeça… if(checkedexception) else … isso é ruim… mais coisa pra aprender e mais coisa pra dar problemas…

G

Rógel, você ainda não me entendeu. EU, em minha opinião, concordo plenamente que apenas unchecked devem fazer rollback. Checked devem ser tratadas sempre e o JTA faz seu trabalho corretamente.

Controverso eu me referi no sentido de que há varias opiniões quanto ao uso de checked e unchecked exceptions. Tem gente que acha que todas as exceptions do Java deveriam ser unchecked, outros acham que está tudo bem… e por aí vai. Ou seja, há diversas opiniões sobre o assunto.

Abraços

rogelgarcia

garcia-jj:
Rógel, você ainda não me entendeu. EU, em minha opinião, concordo plenamente que apenas unchecked devem fazer rollback. Checked devem ser tratadas sempre e o JTA faz seu trabalho corretamente.

Controverso eu me referi no sentido de que há varias opiniões quanto ao uso de checked e unchecked exceptions. Tem gente que acha que todas as exceptions do Java deveriam ser unchecked, outros acham que está tudo bem… e por aí vai. Ou seja, há diversas opiniões sobre o assunto.

Abraços

Eu entendi o que vc quis dizer com o controverso sim… ehehhe

Criado 9 de julho de 2010
Ultima resposta 11 de jul. de 2010
Respostas 26
Participantes 4