본문 바로가기

WEB/SPRING

토비의 스프링 6.1 트랜잭션 코드의 분리

UserService 인터페이스를 생성하고 기존의 UserService 클래스를 UserServiceImpl클래스로 변경한다.

 

트랜잭션이  없는 UserServiceImpl과 트랜잭션 처리가 있는 UserServiceTx클래스를 만들어준다.

 

 

public interface UserService {

    void add(User user);
    void canUpgradeLevels() throws SQLException;
}

 

 

public class UserServiceImpl implements UserService{

    UserDao userDao;

    public static final int MIN_LOGCOUNT_FOR_SILVER = 50;
    public static final int MIN_RECOMMEND_FOR_GOLD = 30;

    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }



    protected void upgradeLevel(User user){
        user.upgradeLevel();
        userDao.update(user);

    }



    public void canUpgradeLevels() throws SQLException {

        List<User> users = userDao.getAll();

        for(User user : users){
            if(canUpgradeLevel(user))
            {
                upgradeLevel(user);
            }
        }


    }


    public boolean canUpgradeLevel(User user){
        Level currentLevel = user.getLevel();

        switch(currentLevel){
            case BASIC : return (user.getLogin() >= MIN_LOGCOUNT_FOR_SILVER);
            case SILVER : return (user.getRecommend() >= MIN_RECOMMEND_FOR_GOLD);
            case GOLD : return false;
            default : throw new IllegalArgumentException("Unknown Level : " + currentLevel);
        }
    }



    public void add(User user){
        if(user.getLevel() == null) user.setLevel(Level.BASIC);
        userDao.add(user);

    }




}

 

public class UserServiceTx implements UserService{

    UserService userService;

    PlatformTransactionManager transactionManager;

    public void setTransactionManager(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    public void setUserService(UserService userService){
        this.userService = userService;
    }


    @Override
    public void add(User user) {
        userService.add(user);
    }

    @Override
    public void canUpgradeLevels() throws SQLException {

        TransactionStatus status = this.transactionManager.getTransaction(new DefaultTransactionDefinition());

        try{
            userService.canUpgradeLevels();

            this.transactionManager.commit(status);
        }catch(RuntimeException e){

            this.transactionManager.rollback(status);
            throw e;
        }


    }
}

 

xml파일로 빈을 생성하고 의존성을 주입해준다.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="driverClass" value="org.mariadb.jdbc.Driver"/>
        <property name="url" value="jdbc:mariadb://localhost:3307/bootex"/>
        <property name="username" value="bootuser"/>
        <property name="password" value="bootuser"/>
    </bean>

    <bean id="userDao" class="spring.dao.UserDaoJdbc">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="userService" class="spring.service.UserServiceTx">
        <property name="userService" ref="userServiceImpl"/>
        <property name="transactionManager" ref="transactionManager"/>
    </bean>

    <bean id="userServiceImpl" class="spring.service.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>

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


</beans>

 

TestUserService와 UserServiceTx에 빈을 주입해주고 테스트하면 트랜잭션이 적용된다.

코드를 고침으로써 얻을 수 있는 이점은 이제 UserServiceImpl에서는 트랜잭션을 신경쓰지 않아도 된다는 점이다.

 

@Test
public void upgradeAllOrNothing(){

    TestUserService testUserService = new TestUserService(users.get(3).getId());
    testUserService.setUserDao(this.userDao);

    UserServiceTx txUserService = new UserServiceTx();
    txUserService.setTransactionManager(transactionManager);
    txUserService.setUserService(testUserService);

    userDao.deleteAll();

    for(User user : users) userDao.add(user);

    try{
        txUserService.canUpgradeLevels();
        fail("TestUserServiceException expected");
    }catch(TestUserServiceException | SQLException e){

    }

    checkLevelUpgraded(users.get(1), false);


}