12 months ago

Hi All, 這次稍微介紹一下SQL Exception處理,原由在於最近看到很多交易動作對於Exception的處理可以說是沒有,草草回傳Boolean是要別人去猜測為什麼會錯嗎?這樣的寫法是不好的,因此這一次我就稍微介紹一下SQL Exception Handle。

Dependencies

compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
testCompile group: 'junit', name: 'junit', version: '4.+'

def sqlVersion = '6.1.0.jre8'
compile group: 'com.microsoft.sqlserver', name: 'mssql-jdbc', version: "${sqlVersion}"

compile group: 'org.apache.commons', name: 'commons-dbcp2', version: "2.0"

FruitDao

這邊簡單的撰寫了一個FruitDao,主要方法為Insert動作而已,但大家可以看到mapFruitException的方法中,有對於SQL Error Code進行處理與包裝,讓其他開發者可以翻閱該Dao文件,即可瞭解這些錯誤訊息。

public class FruitDao {
    
    private BasicDataSource dataSource;
    
    public FruitDao() {
        dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        dataSource.setUrl("jdbc:sqlserver://localhost;databaseName=andy");
        dataSource.setUsername("admin");
        dataSource.setPassword("admin");
    }
    
    public boolean insert(String name, int price) throws FruitException {
        int code = 0;
        
        String sql = "INSERT INTO FRUIT VALUES(?, ?)";
        
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        
        try {
            connection = dataSource.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, name);
            preparedStatement.setInt(2, price);
            
            code = preparedStatement.executeUpdate();
            System.out.println("Code: " + code);
        } catch (SQLException e) {
            System.out.println("Error code: " + e.getSQLState());
            throw mapFruitException(e);
        } finally {
            try {
                preparedStatement.close();
                connection.close();
            } catch (SQLException e) {
                throw mapFruitException(e);
            }
        }
        
        return code > 0;
    }
    
    private FruitException mapFruitException(SQLException sqlException) {
        int fruitErrorCode = 0;
        
        switch (sqlException.getErrorCode()) {
            case 515:
                fruitErrorCode = FruitException.IS_NULL;
                break;
            case 2601:
                fruitErrorCode = FruitException.REPEAT;
                break;
            default:
                fruitErrorCode = 0;
                break;
        }
        
        if(fruitErrorCode != 0) {
            return new FruitException(fruitErrorCode);
        } else {
            return new FruitException(sqlException.getMessage());
        }
    }
}

FruitException

對Exception進行擴充,加入ErrorCode位置,但這個ErrorCode是我們自定義的,目前包含null處理以及重複index的處理。

public class FruitException extends Exception {
    
    private static final long serialVersionUID = 1L;

    public static final int REPEAT = 0;
    
    public static final int IS_NULL = 1;
    
    private int errorCode = 0;
    
    public FruitException(String message) {
        super(message);
    }
    
    public FruitException(int errorCode) {
        this.errorCode = errorCode;
    }

    public int getErrorCode() {
        return errorCode;
    }
    
}

Test

FruitDao fruitDao = new FruitDao();
try {
    System.out.println(fruitDao.insert("Apple", 100));
} catch (FruitException e) {
  switch (e.getErrorCode()) {
    case FruitException.IS_NULL:
      System.out.println("欄位中出現NULL值,請確認欄位數值是否正確,");
      break;
    case FruitException.REPEAT:
      System.out.println("資料發現重複問題,請勿輸入重複資料。");
      break;
    default:
      System.out.println(e.getMessage());
      break;
  }
};

結語

這邊做了一個很簡單的試驗,但ErrorCode這種用法對於大型專案在執行會較好,小型專案就感覺殺雞用牛刀了,但我們也要記得丟出正確的錯誤訊息,讓使用這個Method的同仁或使用者可以瞭解為什麼錯誤,接下來我該如何處理等等。

希望大家可以慢慢培養錯誤處理的好習慣,儘管專案時程緊湊、繁重,該少的也是不能少,但說了那麼多屁話,希望長官還是要用真正的軟體工程思維進行管理,不要再用硬體思維進行管理,底下工城屍都死屍一片了...

Reference

Handling SQLExceptions
Java Code Examples for java.sql.SQLException

← [Spring MVC] CH 3. Spring + Hibernate + JPA [Spring MVC] CH 4.1 Spring Integration UDP →
 
comments powered by Disqus