Não cheguei a testar com um banco só…
Inicialmente eu estava seguindo o guia de integração que é mostrado na apostila FJ-28 da Caelum, mas como precisei dos dois datasources, acabei me desviando.
Não cheguei a testar com um banco só…
Inicialmente eu estava seguindo o guia de integração que é mostrado na apostila FJ-28 da Caelum, mas como precisei dos dois datasources, acabei me desviando.
teste isso por favor.
Beleza, vou testar e digo o resultado!
Obrigado pela atenção! =D
Lucas e mmaico,
Com um só transaction manager o rollback funciona tranquilamente.
applicationContext.xml:
[code]
<tx:annotation-driven />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://.../base" />
<property name="username" value="postgres" />
<property name="password" value="postgres" />
<property name="initialSize" value="5" />
<property name="maxActive" value="5" />
</bean>
<bean id="template" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
[/code]
E na minha classe a única coisa que fiz foi anotar o método com @Transactional e forçar um nullpointer.
então é alguma configuração do atomikos que está errada… não sei se eu consigo ajudar pq nunca mexi com ele…
tenta ir adicionando ele aos poucos até ver onde começa a aparecer o erro
Felizmente tirei o Atomikos de questão. =)
Como nesta fase do projeto iremos apenas fazer inserções em um dos bancos (o outro será apenas consulta), tentei o seguinte:
[code]
<tx:annotation-driven />
<bean id="dataSourceUm" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://.../banco1" />
<property name="username" value="postgres" />
<property name="password" value="postgres" />
<property name="initialSize" value="5" />
<property name="maxActive" value="5" />
</bean>
<bean id="dataSourceDois" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://.../banco2" />
<property name="username" value="postgres" />
<property name="password" value="postgres" />
<property name="initialSize" value="5" />
<property name="maxActive" value="5" />
</bean>
<bean id="dois" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactoryDois"/>
</bean>
<bean id="um" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactoryUm"/>
</bean>
<bean id="sessionFactoryDois" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSourceDois" />
<property name="annotatedClasses">
<list>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="sessionFactoryUm" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSourceUm" />
<property name="annotatedClasses">
<list>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactoryUm"/>
</bean>
[/code]
Mas não obtive sucesso, ele dá o commit de cara. D=
Marcus,
O que acontece se você trocar o seu hibernate template injetado no seu dao por uma session factory, assim:
@Autowired
@Qualifier("um")
protected SessionFactory sessionFactory;
de depois você fazer um this.sessionFactory.getCurrentSession().save(objeto), o getCurrentSession sempre deve ser chamado, nunca o getSession().
Depois me fala o que aconteceu!
se vc usa desse jeito, só a sessionFactoryUm participa da transação, pq só ela tá no transactionManager.
Pra esse DAO sim, mas a idéia é ver se existe alguma outra transação sendo propagada!
Outra questão é verificar se os metodos de persistencia deste Hibernate Template esta usando o getCurrentSession e não o getSession
A ideia é que a apenas a sessionFactoryUm participe da transação por enquanto. Vou fazer o teste com a sessionFactory e dou um retorno.
Grato!
mmaico,
Ao tentar acessar o sessionFactory.getCurrentSession(), lança a seguinte exceção:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Rapaz, fiz um teste em outro Controller, só com um transactionManager e não funcionou. Será que o problema está no meu Controller?
ß) O Spring transactional usa o Spring AOP para gerenciar as transações. O Spring AOP tem uma restrição
forte: para poder decorar suas classes ele usa proxies da Cglib. Esses proxies precisamque sua classe tenha
um construtor sem argumentos, ou que as dependências da sua classe sejam sempre interfaces. E como
programar voltado a interfaces é uma boa prática, pois diminui o acoplamento de uma classe comas suas
dependências, vamos optar pela segunda solução.
Esse Controller problemático extende de uma classe que extende de outra. Seria algum problema nesse sentido? O Controller que funciona não extende de ninguém.
O problema não é a herança, fiz um teste no Controller que funciona, adicionei uma hierarquia e o funcionamento continunou correto. Estranho.
Uma dúvida, pq isso não funciona?
[code]class Classe {
public void metodo1() {
try {
metodo2();
catch (Exception e) {
//...
}
}
@Transactional
public void metodo2() {
//Processamento que lança exceção
}
}[/code]
O escopo da transação não deveria ser o correto funcionamento (ou não) do metodo2()? Pq capturar a exceção no metodo1() influencia no rollback? Se eu tirar o try/catch o rollback funciona.
Grato!
depende da exceção lançada… tenta colocar o transactional num @Component e chamá-lo do controller (de preferencia via interface)…
outra coisa: vc configurou o component-scan com o pacote correto?
Mas meus @Component são DAOs, não faria muito sentido os @Transactional nos DAOs.
O component-scan está correto.
Uma dúvida: Como farei para tratar as exceções se apenas é realizado o rollback quando eu lanço a exceção pro usuário?
claro que faz sentido ter @Transactional nos DAOs… principalmente nos métodos que modificam coisas…
se um método que é @Transactional chama outro que tb é, só uma transação é feita, pode usar sem medo…
faz o teste com o @Transactional no DAO (e não no controller)
Antes todos os @Transactional estavam nos DAOs, mas um método no DAO só realiza uma operação, por exemplo:
@Transactional
public void save(Entity entity) {
hibernateTemplate.save(entity);
}
O @Transactional não faz mais sentido na camada superior?
@Transactional
public void processamento() {
operacao1();
operacao2();
operacao3();
}
Então dando erro, por exemplo, na operacao3(), ele daria rollback em tudo que fez anteriormente.
vc pode ter o transactional nas duas camadas, ele só considera a transação mais externa, por padrão. Colocando no dao vc garante que todos os saves rodam dentro de uma transaction.
Pessoal,
Para entender isso tem que conhecer como o Spring trabalha, e ele faz o seguinte:
Se estiver um @Trasaction no controller ele irá iniciar a transação no controller e propagar para o DAO, quando o metodo no controller finalizar é onde o Spring irá finalizar aquela transação.
Se você colocar um @Transaction no DAO, neste caso não irá impactar em nada porque o perfil transacional default é required, nesse perfil ele usa a transação que já foi propagada do controller
e não cria uma nova. Se você colocasse um @ Transaction com Required New no DAO aiii sim, iria ter 2 transações uma iniciada no controller e outra iniciada no DAO.
Resumo, só @Transaction no DAO não fará efeito algum nesse caso, fará quando um serviço sem transação o chamar como ele irá ver que não existe uma transação corrente ele irá iniciar uma nova.