[Seasar-user:13477] [S2JDBC] NOT NULL制約エラーが発生時、SEntityExistsException

Ryo Miyagi [E-MAIL ADDRESS DELETED]
2008年 3月 29日 (土) 18:35:25 JST


お世話になります。宮城です。

SQL Server 2005の環境で
S2JDBC のエンティティの挿入を実行したときに
NOT NULL制約エラーが発生したときの例外が
SEntityExistsException(一意制約違反)になります。

原因は、
org.seasar.extension.jdbc.dialect.StandardDialect#isUniqueConstraintViolationで
SQLStateの頭2桁が 23, 27, 44 の場合に一意制約違反としているため
NOT NULL制約エラーが発生したときにSQL Server 2005 JDBC Driver が返す
SQLServerExceptionのSQLStateである23000と一致しているためだと思います。
補足:一意制約違反が発生した場合もSQLState:23000を返します。

NOT NULL制約エラーが発生した時の例外が、次になります。
Caused by: org.seasar.framework.exception.SQLRuntimeException: [ESSR0072]SQLで例外(SQL=[insert into t_a (c_a, c_b) values (?, ?)], Message=[[ESSR0072]SQLで例外(SQL=[insert into t_a (c_a, c_b) values (?, ?)], Message=[515], ErrorCode=23000, SQLState={3})が発生しました : [SQLで例外(Message=[テーブル 'hoge.dbo.t_a' の列 'c_a' に値 NULL を挿入できません。この列では NULL 値が許可されていません。INSERT は失敗します。], ErrorCode=515, SQLState=23000)が発生しました。], [テーブル 'hoge.dbo.t_a' の列 'c_a' に値 NULL を挿入できません。この列では NULL 値が許可されていません。INSERT は失敗します。], ErrorCode=515, SQLState=23000)が発生しました

一意制約エラーが発生した時の例外が、次になります。
Caused by: org.seasar.framework.exception.SQLRuntimeException: [ESSR0072]SQLで例外(SQL=[insert into t_a (ID, c_a, c_b) values (?, ?, ?)], Message=[[ESSR0072]SQLで例外(SQL=[insert into t_a (ID, c_a, c_b) values (?, ?, ?)], Message=[2627], ErrorCode=23000, SQLState={3})が発生しました : [SQLで例外(Message=[制約 'PK_t_a' の PRIMARY KEY 違反。オブジェクト 'dbo.t_a' には重複したキーを挿入できません。], ErrorCode=2627, SQLState=23000)が発生しました。], [制約 'PK_t_a' の PRIMARY KEY 違反。オブジェクト 'dbo.t_a' には重複したキーを挿入できません。], ErrorCode=2627, SQLState=23000)が発生しました


NOT NULL制約エラーと一意制約エラーを区別するため
ErrorCodeの値を確認しようと思いますが他にいいアイデアはないでしょうか。


下記に実行環境と再現手順をまとめております。

<実行環境>
OS : WIndows XP Professional SP2
RDBMS : SQL Server 2005 SP2
JDBC Driver : Microsoft SQL Server 2005 JDBC Driver 1.2
s2-framework-2.4.23
s2-extension-2.4.23
s2-tiger-2.4.23

<再現手順>

1.次のテーブルを作成。

CREATE TABLE [dbo].[t_a](
    [c_a] [varchar](50) NOT NULL,
    [c_b] [int] NOT NULL,
    [id] [bigint] IDENTITY(1,1) NOT NULL,
 CONSTRAINT [PK_t_a] PRIMARY KEY NONCLUSTERED (id)
)

2.次のエンティティを作成。

@Entity
@Table(name = "t_a")
public class A {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long id;

    @Column(name = "c_a")
    public String a;

    @Column(name = "c_b")
    public int b;
}

3.次のテストコードを実行する。

    public void testInsertTx() throws Exception {
        A a = new A();
        // not null のDBフィールドにnullを代入
        a.a = null;
        a.b = 2;
        int ret = jdbcManager.insert(a).execute();
        assertEquals(1, ret);
        System.out.println(ret);
    }

→SEntityExistsExceptionが発生。

org.seasar.extension.jdbc.exception.SEntityExistsException: [ESSR0745]エンティティ([E-MAIL ADDRESS DELETED])はすでに存在します (制約違反)。SQL(insert into t_a (c_a, c_b) values (?, ?))
    at org.seasar.extension.jdbc.query.AbstractAutoUpdate.execute(AbstractAutoUpdate.java:93)
    at hoge.entity.ATest.testInsertTx(ATest.java:19)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at junit.framework.TestCase.runTest(TestCase.java:164)
    at org.seasar.framework.unit.S2FrameworkTestCase.doRunTest(S2FrameworkTestCase.java:519)
    at org.seasar.extension.unit.S2TestCase.doRunTest(S2TestCase.java:103)
    at org.seasar.framework.unit.S2FrameworkTestCase.runBare(S2FrameworkTestCase.java:308)
    at junit.framework.TestResult$1.protect(TestResult.java:106)
    at junit.framework.TestResult.runProtected(TestResult.java:124)
    at junit.framework.TestResult.run(TestResult.java:109)
    at junit.framework.TestCase.run(TestCase.java:120)
    at junit.framework.TestSuite.runTest(TestSuite.java:230)
    at junit.framework.TestSuite.run(TestSuite.java:225)
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.seasar.framework.exception.SQLRuntimeException: [ESSR0072]SQLで例外(SQL=[insert into t_a (c_a, c_b) values (?, ?)], Message=[[ESSR0072]SQLで例外(SQL=[insert into t_a (c_a, c_b) values (?, ?)], Message=[515], ErrorCode=23000, SQLState={3})が発生しました : [SQLで例外(Message=[テーブル 'hoge.dbo.t_a' の列 'c_a' に値 NULL を挿入できません。この列では NULL 値が許可されていません。INSERT は失敗します。], ErrorCode=515, SQLState=23000)が発生しました。], [テーブル 'hoge.dbo.t_a' の列 'c_a' に値 NULL を挿入できません。この列では NULL 値が許可されていません。INSERT は失敗します。], ErrorCode=515, SQLState=23000)が発生しました
    at org.seasar.framework.util.PreparedStatementUtil.executeUpdate(PreparedStatementUtil.java:65)
    at org.seasar.extension.jdbc.query.AbstractAutoUpdate.executeInternal(AbstractAutoUpdate.java:123)
    at org.seasar.extension.jdbc.query.AbstractAutoUpdate.execute(AbstractAutoUpdate.java:90)
    ... 21 more
Caused by: org.seasar.framework.exception.SSQLException: [ESSR0072]SQLで例外(SQL=[insert into t_a (c_a, c_b) values (?, ?)], Message=[515], ErrorCode=23000, SQLState={3})が発生しました
    at org.seasar.extension.jdbc.impl.PreparedStatementWrapper.wrapException(PreparedStatementWrapper.java:72)
    at org.seasar.extension.jdbc.impl.PreparedStatementWrapper.wrapException(PreparedStatementWrapper.java:67)
    at org.seasar.extension.jdbc.impl.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:91)
    at org.seasar.framework.util.PreparedStatementUtil.executeUpdate(PreparedStatementUtil.java:63)
    ... 23 more
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: テーブル 'hoge.dbo.t_a' の列 'c_a' に値 NULL を挿入できません。この列では NULL 値が許可されていません。INSERT は失敗します。
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(Unknown Source)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(Unknown Source)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(Unknown Source)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(Unknown Source)
    at com.microsoft.sqlserver.jdbc.TDSCommand.execute(Unknown Source)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(Unknown Source)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(Unknown Source)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(Unknown Source)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(Unknown Source)
    at org.seasar.extension.jdbc.impl.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:89)
    ... 24 more



--------------------------------------
Easy + Joy + Powerful = Yahoo! Bookmarks x Toolbar
http://pr.mail.yahoo.co.jp/toolbar/


Seasar-user メーリングリストの案内