2017-07-24 1 views
0

J'ai écrit un exemple d'application pour tester la gestion des transactions annotées dans Spring (@Transactional).@Transactional ne fonctionne pas lorsque @Autowired s'applique

fichier de contexte;

<?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: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.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> 

<tx:annotation-driven /> 

<context:component-scan base-package="com.test" /> 

<bean id="playerService" class="com.test.service.PlayerServiceImpl" /> 

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 

<bean id="dbUtil" class="com.test.util.DbUtil" init-method="initialize"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="${jdbc.driverClassName}" /> 
    <property name="url" value="${jdbc.url}" /> 
    <property name="username" value="${jdbc.username}" /> 
    <property name="password" value="${jdbc.password}" /> 
</bean> 

<context:property-placeholder location="jdbc.properties"/> 

PlayerDao haricot

import com.test.model.Player; 
import com.test.model.Team; 

public interface PlayerDao { 

public void insertPlayer(Player player); 

public void insertTeam(Team team); 

} 

mise en œuvre de PlayerDaoImpl

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.jdbc.core.JdbcTemplate; 
import org.springframework.stereotype.Repository; 
import org.springframework.transaction.annotation.Propagation; 
import org.springframework.transaction.annotation.Transactional; 

import com.test.model.Player; 
import com.test.model.Team; 

@Repository 
public class PlayerDaoImpl implements PlayerDao{ 

    private JdbcTemplate jdbcTemplate; 

    @Autowired 
    public void setDataSource(DataSource dataSource) { 
     this.jdbcTemplate = new JdbcTemplate(dataSource); 
    } 

    @Transactional (propagation=Propagation.REQUIRED) 
    public void insertPlayer(Player player){ 
     String insertSql ="INSERT INTO PLAYERS (PLAYER_NAME, DOB, AGE, TEAM_ID) VALUES(?,?,?,?);"; 

     jdbcTemplate.update(insertSql,new Object[]{player.getPlayerName(),player.getDob(), player.getAge(), player.getTeamId()}); 
    } 

    @Transactional (propagation=Propagation.REQUIRED) 
    public void insertTeam(Team team){ 
     String insertSql ="INSERT INTO TEAMS (TEAM_ID, TEAM_NAME) VALUES(?,?);"; 

     jdbcTemplate.update(insertSql,new Object[]{team.getTeamId(),team.getTeamName()}); 
    } 

} 

PlayerService

import com.test.model.Team; 

public interface PlayerService { 
    public void createTeam1(Team team) throws Exception; 
    public void createTeam2(Team team) throws Exception; 
} 

PlayerService mise en œuvre

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Service; 

import com.test.model.Team; 
import com.test.persistence.PlayerDao; 

@Service 
public class PlayerServiceImpl implements PlayerService{ 

    @Autowired 
    private PlayerDao playerDao; 

    public void createTeam1(Team team) throws Exception{ 
     playerDao.insertPlayer(team.getPlayers().get(0)); 
     playerDao.insertPlayer(team.getPlayers().get(1)); 
     playerDao.insertPlayer(team.getPlayers().get(2)); 
     playerDao.insertTeam(team); 
    } 

    public void createTeam2(Team team) throws Exception{ 
     playerDao.insertPlayer(team.getPlayers().get(0)); 
     playerDao.insertPlayer(team.getPlayers().get(1)); 

     playerDao.insertTeam(team); 
     throw new Exception(); 
    } 
} 

La classe principale;

import java.time.LocalDate; 
import java.util.ArrayList; 
import java.util.List; 

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

import com.test.model.Player; 
import com.test.model.Team; 
import com.test.service.PlayerService; 

public class TestMain { 



    public static void main(String[] args) { 

     ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); 
     PlayerService playerService = (PlayerService) context.getBean("playerService"); 

     Team t1 = new Team(); 

     t1.setTeamId(1); 
     t1.setTeamName("Team-1"); 

     Player p1 = new Player("Player 1", LocalDate.of(1981,05,02), 1);   
     Player p2 = new Player("Player 2", LocalDate.of(1983,02,15), 1); 
     Player p3 = new Player("Player 3", LocalDate.of(1980,12,31), 1); 

     List<Player> players1 = new ArrayList<Player>(); 
     players1.add(p1); 
     players1.add(p2); 
     players1.add(p3); 

     t1.setPlayers(players1); 

     Team t2 = new Team(); 

     t2.setTeamId(2); 
     t2.setTeamName("Team-2"); 

     Player p4 = new Player("Player 4", LocalDate.of(1989,05,02), 1); 
     Player p5 = new Player("Player 5", null, 1); 

     List<Player> players2 = new ArrayList<Player>(); 
     players2.add(p4); 
     players2.add(p5); 

     t2.setPlayers(players2); 

     try { 
      playerService.createTeam1(t1); 
      playerService.createTeam2(t2); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Transaction fonctionne bien, quand je mets playerDao comme l'une des propriétés du PlayerService dans le fichier de contexte comme ci-dessous (aucun ensemble @Autowired pour playerDao);

<bean id="playerService" class="com.slpl.service.PlayerServiceImpl" > 
    <property name="playerDao" ref="playerDao" /> 
</bean> 

<bean id="playerDao" class="com.slpl.persistence.PlayerDaoImpl"> 
    <property name="jdbcTemplate" ref="jdbcTemplate" /> 
</bean> 

Mais, quand je @Autowired playerDao à la classe PlayerServiceImpl, la transaction n'a pas applique (transaction ne fonctionne pas) et.

Quelle est l'erreur que j'ai commise ici?

+1

Votre transaction doit débuter au niveau du service, elle ne démarre qu'à Dao. Mark Service comme '@ Tansactional' – Rohit

+0

Une raison spécifique d'ajouter @Transactional au niveau de service? – nwGCham

+0

Est-ce que créer une opération atomique d'équipe et de joueur? 'throw new Exception()' dans la méthode de service lorsque votre transaction commence et se termine dans DAO ne provoquera pas une annulation. Qu'entendez-vous par "transaction ne fonctionne pas"? Avez-vous des exceptions ou pas de données dans la base de données? – Rohit

Répondre

0

Cet exemple d'application doit illustrer une transaction Spring utilisant une annotation. La méthode createTeam1() de la classe PlayerServiceImpl crée 3 joueurs et une équipe. Ainsi, une fois l'exécution terminée, il créera 3 lignes dans la table PLAYERS et une ligne dans la table TEAMS. La méthode createTeam2() essaie de créer deux joueurs et une équipe. A la fin de cette méthode, il déclenche une exception qui devrait annuler la création des joueurs et des équipes et NE DOIT PAS créer de lignes dans la table PLAYERS and TEAMS.

L'utilisation de l'annotation @Autowired est correcte pour PlayerDao dans la classe PlayerServiceImpl. Cependant, l'application de la transaction était incorrecte. Comme @ M.Deinum a clairement expliqué le code actuel, créez 7 transactions distinctes en appliquant la transaction directement dans les méthodes DAO (dans ce cas, les méthodes insertPlayer() et insertTeam()). Par conséquent, la manière correcte d'appliquer la transaction est à Méthodes de service (méthodes createTeam1() et createTeam2() dans ce cas).

Pour annuler la transaction lors du lancement d'une exception, l'attribut rollbackfor transaction doit être défini avec l'exception correcte (en tant qu'attribut pour l'annotation @Transactional). Puis retour à la transaction de printemps les modifications lors du lancement d'une exception. Par conséquent, corrigez l'implémentation de la méthode de service comme suit;

@Transactional (propagation=Propagation.REQUIRED, rollbackFor = {Exception.class}) 
public void createTeam1(Team team) throws Exception{ 
    playerDao.insertPlayer(team.getPlayers().get(0)); 
    playerDao.insertPlayer(team.getPlayers().get(1)); 
    playerDao.insertPlayer(team.getPlayers().get(2)); 
    playerDao.insertTeam(team); 
} 

@Transactional (propagation=Propagation.REQUIRED, rollbackFor = {Exception.class}) 
public void createTeam2(Team team) throws Exception{ 
    playerDao.insertPlayer(team.getPlayers().get(0)); 
    playerDao.insertPlayer(team.getPlayers().get(1)); 

    playerDao.insertTeam(team); 
    throw new Exception(); 
}