JPA com Hibernate e Spring

10 respostas
G

Pessoal, bom dia! Eu estou com uma aplicação rodando com JPA/Hibernate. Eu gostaria de criar um segundo persistence-unit para conectar ao SQLServer. Eu tenho encontrado dificuldades na montagem mesmo consultando a documentação. Alguén no fórum poderia me indicar um site ou caso tenham algum modelo, poderiam me ajudar.

Obrigado.

10 Respostas

T

Então, mas qual o problema??? É só vc fazer referência à PU que vc ta usando…

G

Olha o meu persistence.xml

<?xml version="1.0" encoding="UTF-8"?> org.hibernate.ejb.HibernatePersistence java:/painel
<persistence-unit name="sagarf">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/sagarf</jta-data-source>
    <properties>
		<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" />            
        <property name="hibernate.transaction.factory_class"
            value="org.hibernate.ejb.transaction.JoinableCMTTransactionFactory" />
        <property name="hibernate.transaction.manager_lookup_class"
            value="org.hibernate.transaction.JBossTransactionManagerLookup" />
        <!-- <property name="hibernate.hbm2ddl.auto" value="update" /> -->
    </properties>
</persistence-unit>

Bem, eu uso o spring, olha a parte do mapeamento…

<bean id="transactionTemplate"
        class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="jtaTransactionManager" />
    </bean>
    <bean id="entityManagerFactory1"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="painel" />
        <property name="persistenceXmlLocation"
            value="classpath:META-INF/persistence.xml" />
    </bean>

 <bean id="entityManagerFactory2"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="sagarf" />
    <property name="persistenceXmlLocation"
        value="classpath:META-INF/persistence.xml" />
</bean> 

    <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

Eu tenho 2 entityManagerFactory, somente o primeiro persistence-unit a aplicação pega e o segundo vem null, eu ja repliquei, mais não funcionou

G

outra coisa, a minha aplicação só reconhece a primeira unit, como devo fazer para reconhecer as 2?

A

Olá Guilherme, estive passando pelo mesmo problema que o seu, no meu caso uma das entityManagerFactories não conseguia gravar nada, depois de quebrar muito a cabeça cheguei numa configuração que funcionou, peguei do site http://erich.soomsam.net/2007/04/24/spring-jpa-and-jta-with-hibernate-and-jotm/

veja abaixo:

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
    
	<persistence-unit name="persistenceUnit" transaction-type="JTA"/>
  	
</persistence>

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:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

	<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
	
  <bean id="dataSource1" class="org.enhydra.jdbc.standard.StandardXADataSource">
    <property name="transactionManager" ref="jotm"/>
    <property name="driverName" value="net.sourceforge.jtds.jdbc.Driver"/>
    <property name="url" value="jdbc:jtds:sqlserver://localhost/base1"/>
    <property name="user" value="user"/>
    <property name="password" value="senha"/>
  </bean>
  
  <bean id="dataSource2" class="org.enhydra.jdbc.standard.StandardXADataSource">
    <property name="transactionManager" ref="jotm"/>
    <property name="driverName" value="net.sourceforge.jtds.jdbc.Driver"/>
    <property name="url" value="jdbc:jtds:sqlserver://localhost/base2"/>
    <property name="user" value="user"/>
    <property name="password" value="senha"/>
  </bean>
  
	<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
  
	<bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
		<property name="userTransaction" ref="jotm" />
		<property name="allowCustomIsolationLevels" value="true" />
	</bean>
  
	<bean id="entityManager1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	
		<property name="dataSource" ref="dataSource1" />
		
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="database" value="SQL_SERVER" />
				<property name="databasePlatform" value="org.hibernate.dialect.SQLServerDialect" />
			</bean>
		</property>
		
		<property name="jpaPropertyMap">
			<map>
				<entry key="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JOTMTransactionManagerLookup" />
				<entry key="hibernate.transaction.flush_before_completion" value="true" />
				<entry key="hibernate.transaction.auto_close_session" value="true" />
				<entry key="hibernate.current_session_context_class" value="jta" />
				<entry key="hibernate.connection.release_mode" value="auto" />
			</map>
		</property>
		
    <property name="jpaDialect">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
		</property>
		
		<property name="persistenceUnitPostProcessors">
			<bean class="br.service.JtaPersistenceUnitPostProcessor">
				<property name="jtaDataSource" ref="dataSource1" />
			</bean>
		</property>
	</bean>
	
	<bean id="entityManager2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	
		<property name="dataSource" ref="dataSource2" />
		
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="database" value="SQL_SERVER" />
				<property name="databasePlatform" value="org.hibernate.dialect.SQLServerDialect" />
			</bean>
		</property>
		
		<property name="jpaPropertyMap">
			<map>
				<entry key="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JOTMTransactionManagerLookup" />
				<entry key="hibernate.transaction.flush_before_completion" value="true" />
				<entry key="hibernate.transaction.auto_close_session" value="true" />
				<entry key="hibernate.current_session_context_class" value="jta" />
				<entry key="hibernate.connection.release_mode" value="auto" />
			</map>
		</property>
		
		<property name="jpaDialect">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
		</property>
		
		<property name="persistenceUnitPostProcessors">
			<bean class="br.service.JtaPersistenceUnitPostProcessor">
				<property name="jtaDataSource" ref="dataSource2" />
			</bean>
		</property>
	</bean>
	
	<tx:annotation-driven transaction-manager="jtaTransactionManager" proxy-target-class="false" />
	
	<bean id="clienteService" class="br.service.cliente.ClienteServiceImpl">
		<property name="entityManagerFactory" ref="entityManager1"/>
	</bean>
	
	<bean id="usuarioService" class="br.service.usuario.UsuarioServiceImpl">
		<property name="entityManagerFactory" ref="entityManager2"/>
	</bean>
	
</beans>

E ainda, a classe JtaPersistenceUnitPostProcessor:

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;

public class JtaPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {

	private DataSource jtaDataSource;

	public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo mutablePersistenceUnitInfo) {
		mutablePersistenceUnitInfo.setJtaDataSource(getJtaDataSource());
	}
	
	public DataSource getJtaDataSource() {
		return jtaDataSource;
	}
	
	@Required
	public void setJtaDataSource(DataSource jtaDataSource) {
		this.jtaDataSource = jtaDataSource;
	}

}
G

Agradeço vc pela ajuda. Eu montei essa infra-estrutura, estou com uns erros com o SQL-Server, mais é questão de bibliotecas que estão faltando no Jboss. Te pergunto o seguinte, para configurar o postgresql como devo definir o nome na property? Eu usei PostgreSQL, mais deu erro, não consegue converter para String.
Eu comentei o do Postgresql e o SQL_SERVER passou na boa.

obrigado.

A

é que eu acho que tem que ser tudo em maiúsculo, dei uma olhada no método dessa classe (HibernateJpaVendorAdapter):

/**
	 * Determine the Hibernate database dialect class for the given target database.
	 * @param database the target database
	 * @return the Hibernate database dialect class, or <code>null<code> if none found
	 */
	protected Class determineDatabaseDialectClass(Database database) {
		switch (database) {
			case DB2: return DB2Dialect.class;
			case DERBY: return DerbyDialect.class;
			case H2: return H2Dialect.class;
			case HSQL: return HSQLDialect.class;
			case INFORMIX: return InformixDialect.class;
			case MYSQL: return MySQLDialect.class;
			case ORACLE: return Oracle9Dialect.class;  // deprecated since Hibernate 3.2.5 - to be updated in Spring 3.0
			case POSTGRESQL: return PostgreSQLDialect.class;
			case SQL_SERVER: return SQLServerDialect.class;
			case SYBASE: return SybaseDialect.class;
			default: return null;
		}
	}

e no Enum das Database:

/**
 * Enumeration for common database platforms. Allows strong typing of database type
 * and portable configuration between JpaVendorDialect implementations.
 *
 * <p>If a given PersistenceProvider supports a database not listed here,
 * the strategy class can still be specified using the fully-qualified class name.
 * This enumeration is merely a convenience. The database products listed here
 * are the same as those explicitly supported for Spring JDBC exception translation
 * in <code>sql-error-codes.xml</code>.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 2.0
 * @see AbstractJpaVendorAdapter#setDatabase
 */
public enum Database {

	DEFAULT,

	DB2,

	DERBY,

	H2,

	HSQL,

	INFORMIX,

	MYSQL,

	ORACLE,

	POSTGRESQL, 

	SQL_SERVER,

	SYBASE

}

Então eu acho que vc deve usar [color=green]POSTGRESQL[/color]

G

obrigado pela ajuda, o nome é em maiúsculo mesmo. Veja se vc pode me orientar. Eu estou usando annotations.

no entityManagerFactory1 eu acesso o PostgreSQL
Eu tenho uma classe chama ProjetoVO que tem essa anotação.
Essa classe é acessada pelo postgresql, esta funcionando ok.

@Entity
@Table(name = “projeto”)

Agora eu criei o entityManagerFactory2 e eu acesso o SQL Server
Eu tenho uma classe chamada EmpreendimentoVO que tem essa anotação.
Essa classe pertence ao SQL Server.
@Entity
@Table(name=“TbEmpreendimentos”)

Quando eu faço o deploy o dar o seguinte erro:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory1’ defined in ServletContext resource [/WEB-INF/conf/applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: br.teste.aplicacaoejb3.vo.EmpreendimentoVO

O entityManagerFactory1 tenta achar essa tabela mapeada no EmpreendimentoVO no Postgresql, mais é do SQL server. Como faço para distinguir, ja olhei algumas anotaçães.

Obrigado. Guilherme

A

Então, todo o negócio está em qual o EntityManagerFactory você injetou, por exemplo, conforme a configuração acima do springContext, temos dois entityManagersFactory, assim, minha classe ClienteServiceImpl que recebe entityManager1 (que referencia a base 1) poderia ser assim:

public class ClienteServiceImpl {
  
  //entityManagerFactory referente a conexão com a base 1
  private EntityManagerFactory entityManagerFactory;
  
  private EntityManager em;
  
  public setEmf(EntityManagerFactory entityManagerFactory) {
    this.entityManagerFactory = entityManagerFactory
    this.em = entityManagerFactory.createEntityManager();
  }
  
  public void saveCliente(Cliente cliente) {
    em.persist(cliente);
  }

}

O mesmo para a classe UsuarioServiceImpl, só que ela receberia o entityManager2, então estaria manipulando os dados da base 2. O negócio não está nos annotations, mas sim em qual emf vc injeta, você não poderia fazer um “from Cliente” usando o entityManagerFactory2, eu acho que esse erro é porque você está tentando usar a injeção automática do EntityManager que o Spring faz, quando por exemplo você tem:

@Transacional
public class Cliente {
  
  private EntityManager em;
  
	@PersistenceContext
	public void setEm(EntityManager em) {
		this.em = em;
	}
}
G

Meu caro, resolvi o problema, faltou o @id no annotations, agora esta 100%. Eu irei montar um tutorial e disponibilizar para a comunidade.

Obrigado.

abçs. Guilherme Freitas

A

eheheh… verdade… o famigerado @Id!

Legal vc montar o tutorial, foi realmente muito difícil encontrar essa solução.

Criado 1 de julho de 2008
Ultima resposta 4 de jul. de 2008
Respostas 10
Participantes 3