Spring Framework における SQLException(HibernateException.cause) の変換
MySQL で InnoDB を使って外部キー制約を張ることにした。
そこで、制約違反を検出したとき、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 というファイルをクラスパスのルートに設置。
1054,1064,1146 1062,1216
このファイルはデフォルトで spring.jar に含まれているが、InnoDBの追加機能である外部キー制約違反のエラーコード(1216)を含んでいなかったので、自分でオーバーライドしなくてはならなかった。
プロパティの設定に順番が影響するのがちょっと嫌だけど、ひとまずこれでしのげそう。