Spring Framework における SQLException(HibernateException.cause) の変換

MySQLInnoDB を使って外部キー制約を張ることにした。
そこで、制約違反を検出したとき、Spring Framework が適切に org.springframework.dao.DataIntegrityViolationException を throw できるか検証してみた。

結果 → 失敗

org.springframework.jdbc.UncategorizedSQLException が throw されている。

ソースコードを読んでみると、SQLException の例外を変換するのは HibernateAccessor のプロパティである、jdbcExceptionTranslator のようだ。そして、これはデフォルトで org.springframework.jdbc.support.SQLStateSQLExceptionTranslator のインスタンスのようだ。ここを適切に定義してあげればよさそう。

探してみると、同じインターフェースを実装した org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator というのがある。こちらはなかなか多機能そうで、単純に切り替えてあげれば動きそう。

そこで、HibernateDaoSupport のサブクラスに jdbcExceptionTranslator プロパティを定義し、実際には内部の HibenateTemplate にセットするように作ってみた。

public class HibernatePollingStation
    extends HibernateDaoSupport
    implements PollingStation {

    public final SQLExceptionTranslator getJdbcExceptionTranslator() {
        return getHibernateTemplate().getJdbcExceptionTranslator();
    }

    public final void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
        getHibernateTemplate().setJdbcExceptionTranslator(
            jdbcExceptionTranslator);
    }

applicationContext.xml

さらに、sql-error-codes.xml というファイルをクラスパスのルートに設置。

sql-error-codes.xml



  
    1054,1064,1146
    1062,1216
  
  

このファイルはデフォルトで spring.jar に含まれているが、InnoDBの追加機能である外部キー制約違反のエラーコード(1216)を含んでいなかったので、自分でオーバーライドしなくてはならなかった。

プロパティの設定に順番が影響するのがちょっと嫌だけど、ひとまずこれでしのげそう。