참조 : Spring 프레임워크 워크북

이번에는 DAO 계층이 아닌 Service 계층으로 트랜잭션 책임을 다시 가져왔습니다. 따라서 서비스 계층이 이 전글에 비하면 좀 더 복잡해 졌습니다. 게다가 쌩 JDBC를 사용하고, 거기다 트랜잭션 처리도 AOP 사용해서 모듈화 하지 않았기 때문에 코드는 다음과 같이 다소 복잡합니다.

public class MemberServiceImplTransactionInBusiness implements MemberService{

    private MemberDao memberDao;

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    public void add(Member member) throws SQLException {

        Connection con = null;
        try {
            con = dataSource.getConnection();
            con.setAutoCommit(false);
            memberDao.add(con, member);
            //TODO 예외발생
            TransactionTestingUtil.generateSQLExceptionMethod();
            con.commit();
        }
        catch (SQLException e) {
            if(con != null)
                con.rollback();
            throw e;
        }
        finally {
            if(con != null)
                con.close();
        }
    }

}

add()메소드에서 해야할 일은 딱 두 줄(파란색)임에도 불구하고 여러 줄의 코드가 정신없이 널려있습니다. DAO 코드를 보겠습니다.

public class MemberDaoJdbcTransactionInBusiness implements MemberDao {

    public void add(Member member) {
        throw new UnsupportedOperationException();
    }

    public void add(Connection con, Member member) throws SQLException {
        StringBuilder addMemberQuery = new StringBuilder();
        addMemberQuery.append("INSERT INTO Member(id, password, name, email) ");
        addMemberQuery.append("VALUES (?, ?, ?, ?)");

        try {
            PreparedStatement pstmt = con.prepareStatement(addMemberQuery.toString());
            pstmt.setString(1, "whiteship3");
            pstmt.setString(2, "pass");
            pstmt.setString(3, "기선");
            pstmt.setString(4, "keesun3@email.com");
            pstmt.executeUpdate();
        }
        catch (SQLException e) {
            throw e;
        }
    }

}

JDBC 코딩이 별로 재미도 없고 복잡합니다. 서비스 계층에서 사용하던 connection 객체를 그대로 이어 받아서 사용합니다. 그리고 만약 복잡한 SQL을 사용했을 떄 DB가 바껴버리면 그 복잡한 SQL들을 다 어떻게 관리할지 걱정이 됩니다.

테스트코드는 이전 글과 동일합니다. Spring 설정파일은 다음과 같습니다.

    <bean id="memberService" class="com.bookbuying.member.service.MemberServiceImplTransactionInBusiness">
        <property name="dataSource" ref="dataSource" />
        <property name="memberDao" ref="memberDao" />
    </bean>

    <bean id="memberDao" class="com.bookbuying.member.dao.MemberDaoJdbcTransactionInBusiness" />

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${db.driver}"/>
        <property name="jdbcUrl" value="${db.url}"/>
        <property name="user" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
    </bean>

다음 글에서는 Spring의 Transaction 관련 주요 API들(TransactionDefinition, TransactionStatus, PlatformTransactionManager)을 사용하여 구현하겠습니다.