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);
}
'WEB > SPRING' 카테고리의 다른 글
토비의 스프링 7.1 SQL과 DAO의 분리 (0) | 2024.02.13 |
---|---|
6.5 스프링 AOP (1) | 2024.02.10 |
토비의 스프링 5.2 트랜잭션 서비스 추상화 (0) | 2024.01.30 |
토비의 스프링 5.1 서비스 추상화 (0) | 2024.01.29 |
토비의 스프링 파트 4 예외 (0) | 2024.01.23 |