java 사무 학습 노트 (3) - 추한 사례

4564 단어
본 시리즈의 이전 글에서 우리는 전형적인 사무 처리 실패 사례를 보았다. 그 주요 원인은 서비스 층과 각 DAO가 사용하는 연결이 다르고 JDBC에서 사무 처리의 역할 대상은 바로 연결의 대상이기 때문에 DAO의 조작과 같은 사무에 있지 않아 사무 실패를 초래했다.이 과정에서 우리는 이러한 실패를 피하려면 모든 조작이 하나의 연결 대상을 공유할 수 있기 때문에 문제가 없을 것이다.
 
이 기사의 github 소스 코드를 다운로드하려면 다음과 같이 하십시오.
git clone https://github.com/davenkin/java_transaction_workshop.git
 
이 글에서 우리는 성공적이지만 추악한 사무 처리 방안을 보게 될 것이다. 그의 기본적인 사고방식은 서비스 층에서 연결 대상을 만들고 이 연결을 각각의 DAO 클래스에 전달하면 연결 공유의 목적을 완성할 수 있다는 것이다.
 
두 개의 DAO 클래스를 수정하여 하나의 Connection 객체에 적용합니다. UglyBankDao 클래스는 다음과 같습니다.
public class UglyBankDao
{
    public void withdraw(int bankId, int amount, Connection connection) throws SQLException
    {
        PreparedStatement selectStatement = connection.prepareStatement("SELECT BANK_AMOUNT FROM BANK_ACCOUNT WHERE BANK_ID = ?");
        selectStatement.setInt(1, bankId);
        ResultSet resultSet = selectStatement.executeQuery();
        resultSet.next();
        int previousAmount = resultSet.getInt(1);
        resultSet.close();
        selectStatement.close();
         
        int newAmount = previousAmount - amount;
        PreparedStatement updateStatement = connection.prepareStatement("UPDATE BANK_ACCOUNT SET BANK_AMOUNT = ? WHERE BANK_ID = ?");
        updateStatement.setInt(1, newAmount);
        updateStatement.setInt(2, bankId);
        updateStatement.execute();
         
        updateStatement.close();
    }
}

같은 방법으로 UglyInsuranceDao 클래스를 정의합니다.
public class UglyInsuranceDao
{
    public void deposit(int insuranceId, int amount, Connection connection) throws SQLException
    {
        PreparedStatement selectStatement = connection.prepareStatement("SELECT INSURANCE_AMOUNT FROM INSURANCE_ACCOUNT WHERE INSURANCE_ID = ?");
        selectStatement.setInt(1, insuranceId);
        ResultSet resultSet = selectStatement.executeQuery();
        resultSet.next();
        int previousAmount = resultSet.getInt(1);
        resultSet.close();
        selectStatement.close();
        
        
        int newAmount = previousAmount + amount;
        PreparedStatement updateStatement = connection.prepareStatement("UPDATE INSURANCE_ACCOUNT SET INSURANCE_AMOUNT = ? WHERE INSURANCE_ID = ?");
        updateStatement.setInt(1, newAmount);
        updateStatement.setInt(2, insuranceId);
        updateStatement.execute();
        
        updateStatement.close();
    }
}

그리고 서비스 클래스를 수정합니다. Ugly Bank 서비스 클래스의transfer 방법에서 먼저 연결 대상을 만들고 그 대상을 Ugly BankDao에 순서대로 전달하는 withdraw 방법과 Ugly Insurance Dao 클래스의 deposit 방법으로 서비스 층과 DAO 층이 같은 연결 대상을 사용하도록 합니다.UglyBankService 클래스를 다음과 같이 정의합니다.
public class UglyBankService implements BankService
{
    private DataSource dataSource;
    private UglyBankDao uglyBankDao;
    private UglyInsuranceDao uglyInsuranceDao;
      
    public UglyBankService(DataSource dataSource)
    {
        this.dataSource = dataSource;
    }
      
    public void transfer(int fromId, int toId, int amount)
    {
        Connection connection = null;
        try
        {
            connection = dataSource.getConnection();
            connection.setAutoCommit(false);
      
            uglyBankDao.withdraw(fromId, amount, connection);
            uglyInsuranceDao.deposit(toId, amount, connection);
      
            connection.commit();
        } catch (Exception e)
        {
            try
            {
                assert connection != null;
                connection.rollback();
            } catch (SQLException e1)
            {
                e1.printStackTrace();
            }
        } finally
        {
            try
            {
                assert connection != null;
                connection.close();
            } catch (SQLException e)
            {
                e.printStackTrace();
            }
        }
    }
      
    public void setUglyBankDao(UglyBankDao uglyBankDao)
    {
        this.uglyBankDao = uglyBankDao;
    }
      
    public void setUglyInsuranceDao(UglyInsuranceDao uglyInsuranceDao)
    {
        this.uglyInsuranceDao = uglyInsuranceDao;
    }
}

위에서 Connection 대상을 공유하는 방법은 업무 처리의 목적을 완성할 수 있지만 이런 방법은 추악한 것이다. 이유는 업무 처리의 목적을 완성하기 위해 우리는 서비스 층과 DAO 층 사이에 밑바닥의 Connection 종류를 전달해야 하고 DAO 층의 방법도 이 Connection 대상을 받아들여야 하기 때문이다. 이런 방법은 분명히 좋지 않다. 이것이 바로 전형적인 API 오염이다.
 
다음 블로그에서 우리는 커넥션 대상을 전달하지 않은 상황에서 본문과 같은 사무 처리 기능을 어떻게 완성하는지 이야기할 것이다.
전재 주소:http://www.davenkin.me/post/2013-02-22/40049367747

좋은 웹페이지 즐겨찾기