Spring 3 e Hibernate 4

Pessoal,

estou começando a usar Spring 3 com Hibernate 4 baseando no excelente artigo http://it4beginners.wordpress.com/2012/10/05/spring-3-and-hibernate-4-for-beginners/

e me surgiu uma dúvida a respeito de como o Spring gerência as transações ao final do post vou explicitar a dúvida,

vou postar abaixo os arquivos e códigos para melhor entendimento, e vai servir até de exemplo para quem quiser estudar :wink:

Ferramentas e Tecnologias utilizadas:

  • Maven 3.0.5
  • jdk1.7.0_15
  • Eclipse Juno
  • Spring orm 3.2.2
  • Hibernate 4.1.10
  • PostgreSQL 9.2

A classe entidade “Usuario”

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table
public class Usuario implements Serializable {

	private static final long serialVersionUID = 3007826345280433076L;
	
	@Id
	private String email;
	private String senha;
	private String nomeCompleto;
	
	@Column(name="email", unique = true, nullable = false, length = 64)
	public String getEmail() {
		return email;
	}
	
	public void setEmail(String email) {
		this.email = email;
	}
	
	@Column(name = "senha", nullable = false, length = 16)
	public String getSenha() {
		return senha;
	}
	
	public void setSenha(String senha) {
		this.senha = senha;
	}
	
	@Column(name = "nome_completo", nullable = false, length = 128)
	public String getNomeCompleto() {
		return nomeCompleto;
	}
	
	public void setNomeCompleto(String nomeCompleto) {
		this.nomeCompleto = nomeCompleto;
	}	
	
}

A classe genérica abstrata DAO “AbstractHibernateDAO”

package br.com.netinspector.model.dao;

import java.io.Serializable;
import java.util.List;

import com.google.common.base.Preconditions;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public abstract class AbstractHibernateDAO< T extends Serializable> {
	
	private final Class< T> clazz;
    @Autowired
    SessionFactory sessionFactory;
 
    public AbstractHibernateDAO(final Class< T> clazzToSet) {
        this.clazz = clazzToSet;
    }
 
    @SuppressWarnings("unchecked")
	public T getById(final Long id) {
        Preconditions.checkArgument(id != null);
        return (T) this.getCurrentSession().get(this.clazz, id);
    }
 
    @SuppressWarnings("unchecked")
	public List< T> getAll() {
        return this.getCurrentSession()
                .createQuery("from " + this.clazz.getName()).list();
    }
 
    public void create(final T entity) {
        Preconditions.checkNotNull(entity);
        this.getCurrentSession().persist(entity);
    }
 
    public void update(final T entity) {
        Preconditions.checkNotNull(entity);
        this.getCurrentSession().merge(entity);
    }
 
    public void delete(final T entity) {
        Preconditions.checkNotNull(entity);
        this.getCurrentSession().delete(entity);
    }
 
    public void deleteById(final Long entityId) {
        final T entity = this.getById(entityId);
        Preconditions.checkState(entity != null);
        this.delete(entity);
    }
 
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
 
    protected final Session getCurrentSession() {
        return this.sessionFactory.getCurrentSession();
    }

}

Classe DAO “UsuarioDAO”

package br.com.netinspector.model.dao;

import br.com.netinspector.model.domain.Usuario;

public class UsuarioDAO extends AbstractHibernateDAO<Usuario> {

	public UsuarioDAO() {
		super(Usuario.class);
	}

}

O arquivo de configuração do Spring “ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       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.2.xsd
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">      
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.postgresql.Driver" />
        <property name="url" value="jdbc:postgresql://localhost:5432/db_netinspector" />
        <property name="username" value="netinspector" />
        <property name="password"  value="**********" />
    </bean>
    
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
        <property name="dataSource" ref="dataSource" />
        <!-- Don't forget to list all your entity classes here -->
        <property name="annotatedClasses">
            <list>
                <value>br.com.netinspector.model.domain.Usuario</value>
            </list>
        </property>
 
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.default_schema">netinspector</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>     
    
    <bean id="txManager"
          class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="txManager" />
     
    <context:annotation-config />
     
    <!-- Note the usage of abstract="true" and parent="AbstractHibernateDAO" in the implementations-->
    <bean id="AbstractHibernateDAO" abstract="true"
          class="br.com.netinspector.model.dao.AbstractHibernateDAO"/>
     
    <bean id="UsuarioDAO" parent="AbstractHibernateDAO"
          class="br.com.netinspector.model.dao.UsuarioDAO"/>
</beans>

a classe APP.java para executar inserindo um registro no banco

package br.com.netinspector;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import br.com.netinspector.model.dao.UsuarioDAO;
import br.com.netinspector.model.domain.Usuario;

public class App {
	
	public static void main(String[] args) {
		
		ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
		
		Usuario usuario = new Usuario();
		usuario.setEmail("Andrelosquei@com.br");
		usuario.setNomeCompleto("Andrelosquei Da Silva");
		usuario.setSenha("12322");
		
		UsuarioDAO usuarioDAO = (UsuarioDAO) context.getBean("UsuarioDAO");
		usuarioDAO.create(usuario);	
		
		
	}

}

Esse pequena aplicação está funcionando e o registro está sendo inserido de boa, agora vamos a minha dúvida:


Será que está sendo feito o controle da transação?? Pois se repararem não há nenhuma chamada explícita(pelo menos no código) de “beginTransaction” “commit” etc

Será que a parte do arquivo de conf “ApplicationContext.xml” é responsável pelo gerenciamento da transação?

<bean id="txManager"
          class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="txManager" />

Abraços,

Rogério Martins Manzan

Nesse seu exemplo, não está. Primeiro de tudo, retire o @Transactional de cima da classe. Coloque-o em cima dos metodos que queres que sejam controlados pelo Spring. Lembrando que esse @Transactional, possui um parametro readonly, onde vc colocando igual a “true”, você irá dizer ao spring que esse metodo só vai fazer leitura.

Para uma arquitetura mais robusta, coloque uma camada de serviço, representada pelo @Service e lá coloque o @Transactional em cima dos métodos.

Sobre a chamada explicita, você não vera, ela é transparente.

Veja este artigo que explica algumas annotations do spring e correlatos: http://heyxampis.com/2012/10/29/annotations-spring/

darksteel3000,

obrigado pela força, li o seu artigo sobre Annotations Spring esclareceu bastante e li também a documentação do Spring.

Pelo que entendi então devo colocar a anotação @Transacional com o parâmetro “readOnly” nos métodos que requerem contexto transacional.

Logo nos métodos “save”, “update” e “delete” o parâmetro apropriado será “readOnly=false”. Correto?

Abs,

Rogério Martins Manzan

O readonly = false, não precisa, pois o false é default.

Oi gente, vocês poderiam me auxiliar com esse erro que venho encarando.
Estou utilizando o spring 3.2.2.RELEASE e hibernate 3.6.0.Final. Estou obtendo um erro ao definir o bean sessionFactory não estou sabendo qual deve ser a classe que ele deve se referenciar. Eu já sei que ele não deve ser o org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean. Então qual é a classe?

Obrigado qualquer resposta
Frederico