Question

J'ai essayé de configurer la gestion des transactions déclaratives dans mon application Web basée sur Spring et il refuse de coopérer avec moi.

J'ai deux problèmes principaux:

  1. Définition de DefaultAutoCommit sur False sur notre source de données (dont nous avons besoin pour notre application) provoque tout requêtes en arrière, avec ou sans transactions impliquées.
  2. Les transactions sont configurées et des classes proxy ainsi que des méthodes transactionnelles sont créées, mais aucune transaction ne semble utilisée.

Le premier problème est plutôt perplexe, car chaque requête individuelle est en cours de retour dans la base de données. Cela inclut également des instructions. Qu'est-ce qui pourrait entraîner le retour de chaque requête dans la base de données?

Quant au deuxième problème, ma configuration de la gestion des transactions est décrite ci-dessous:

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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/spring-context-3.0.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
       default-autowire="byName">

<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
  <!-- the transactional semantics... -->
  <tx:attributes>
    <!-- other methods use the default transaction settings (see below) -->
    <tx:method name="*" rollback-for="Exception" />
  </tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
 of an operation defined by a service in the service package -->
<aop:config>
  <aop:pointcut id="serviceOperations" expression="execution(* foo.bar.service.*.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperations"/>
</aop:config>

<!-- similarly, don't forget the PlatformTransactionManager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="defaultAutoCommit" value="false" />
</bean>

<bean id="fooService" class="foo.bar.service.FooService" />

<bean id="barService" class="foo.bar.service.BarService" />

<bean id="zapService" class="foo.bar.service.ZapService" />

</beans>

À partir de tous les tutoriels et forums que j'ai visités pour essayer de résoudre ce problème, je crois que ma configuration devrait être correcte. Cependant, je ne comprends pas entièrement les transactions AOP et Spring, donc je manque quelque chose de crucial.

Comme mentionné ci-dessus, je peux retracer mes journaux et voir des proxys, ainsi que des méthodes transactionnelles, créées pour mes cours de service. Cependant, lorsque j'exécute l'application et que je trace via les journaux, je ne vois aucune instruction traitant du DataSourcetransactionManager ou des transactions créées, engagées, renvoyées, etc.

Il me semble que rien n'est réellement dirigé, et je suis terriblement confus car j'ai suivi de nombreux tutoriels différents et essayé de nombreuses façons différentes, mais cela finit toujours par cette situation.

Je suis également assez certain que mes propriétés log4j ont configuré correctement pour recevoir des messages du DataSourceTransactionManager, mais je les fournit ci-dessous pour m'assurer qu'il ne s'agit pas seulement d'une erreur de journalisation de ma part.

Mon log4j est configuré avec les journalistes suivants pour essayer de retracer les transactions:

log4j.logger.org.springframework=INFO, file
log4j.logger.org.springframework.jdbc.datasource=DEBUG, file
log4j.logger.org.springframework.transaction=DEBUG, file

Remarque: j'ai exécuté le journal supérieur sur le débogage à un moment donné, et c'est là que j'ai vérifié que les procurations de service ont été créées.

Quelqu'un a-t-il un aperçu de ce qui pourrait se passer? Je suis plutôt coincé pour le moment, car je vois certaines pièces impliquées dans la création de transactions, mais je ne vois aucun signe de transaction utilisé.

Éditer:

Informations supplémentaires demandées par JB Nizet.

L'ensemble de mon application est axé sur l'annotation et donc mes haricots de service sont annotés avec @Service et injectés dans mes contrôleurs via un automatique basé sur des noms.

Ci-dessous est un exemple de l'une de mes classes de service (les noms ont été modifiés mais refléteront mon applicationContext.xml).

@Service("zapService")
public class ZapService
{

    /**
     * Data access object which performs the database look up
     */
    private ZapDAO zapDAO;

    /**
     * Add the given zap to the database
     *
     * @param zap a populated zap
     */
    public void processNewZap(Zap zap)
    {
        zapDAO.processNewZap(zap);
    }
}

Comme vous pouvez le voir, mes cours de service sont simplement des proxys entre les classes de contrôleur et les classes DAO. Les DAO sont l'endroit où je gère réellement les connexions de la base de données.

Je crois que j'ai lu quelque part que rendre les services transactionnels, plutôt que les classes DAO, était une pratique préférée lorsqu'il s'agit de transactions. S'il vous plait corrigez moi si je me trompe.

La classe Zapdao est décrite ci-dessous.

@Repository("zapDAO")
public class ZapDAO
{

    /**
     * Log4j logger for this class
     */
    Logger logger = Logger.getLogger(ZapDAO.class);

    /**
     * Spring jdbc object to handle interacting with the database
     */
    private JdbcTemplate jdbcTemplate;

    public void processNewZap(Zap zap) {

        ... query constructing logic ...

        this.jdbcTemplate.update(INSERT_ZAP_QUERY_SQL);

    }

    public void setDataSource(DataSource dataSource)
    {
        Assert.notNull(dataSource, "You must supply a valid data source");

        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
}

J'utilise un JDBCTemplate pour gérer mes connexions et mes requêtes.

Était-ce utile?

La solution

Donc, après des heures et des heures de recherche, de débogage et de me déchirer les cheveux, je suis finalement tombé sur cette Petit gemme qui a fourni toutes les réponses.

Je n'aurais jamais soupçonné quelque chose comme ça pour être le problème, mais suivre les étapes décrites dans le lien ci-dessus a parfaitement fonctionné.

À l'intérieur de mon Dispatch-Servlet.xml, j'avais initialement déclaré mon composant-ball comme suit:

<context:component-scan base-package="foo.bar"/>

Qui est un package parent de tous mes haricots d'application. Ainsi, comme décrit dans le lien ci-dessus, Spring était en train d'écraser mes beans de service transactionnels à partir de l'applicationContext.xml avec les beans de service à partir de Dispatcher-Servlet.xml qui ne connaissaient pas les transactions.

Tout ce que j'ai fait, c'est de briser l'échelle de composant ci-dessus pour scanner uniquement les dossiers qui contenaient des haricots non transactionnels.

<context:component-scan base-package="foo.bar.controller"/>
<context:component-scan base-package="foo.bar.model"/>
<context:component-scan base-package="foo.bar.service.display"/>
<context:component-scan base-package="foo.bar.service.security"/>

<!-- foo.bar.service gets scanned in applicationContext.xml and includes 
transactions so we must make sure to not include it here. The transactional beans
will be overridden in that case -->

Après cela, mes transactions ont fonctionné exactement comme prévu et je voyais enfin des empreintes de pas des transactions et du DataSourcetransactionManager dans mes fichiers journaux. Cela a également résolu mon premier problème initial des recul automatique dans la base de données. Je suppose que cela doit être étroitement lié au manque de transactions.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top