質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.55%

SpringBatch+iBatisでのOracle XMLTYPE型の取扱いについて

受付中

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 1,978

keisukestrat

score 11

前提・実現したいこと

SpringBatch+iBatisを使用し、OracleのXMLTYPE型にINSERT/UPDATE/SELECTを行いたいと思っております。
容量の小さなXMLファイルをStringとして読み込み値をINSERTした場合は、正常に登録されますが、
ある容量以上のファイルになると下記エラーが発生します。

発生している問題・エラーメッセージ

org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [72000]; error code [1461]; ORA-01461: LONG値はLONG列にのみバインドできます。
; nested exception is java.sql.BatchUpdateException: ORA-01461: LONG値はLONG列にのみバインドできます。
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:212)
    at org.springframework.batch.item.database.IbatisBatchItemWriter.write(IbatisBatchItemWriter.java:122)
    at org.springframework.batch.item.support.CompositeItemWriter.write(CompositeItemWriter.java:50)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:171)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:150)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:268)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:194)
    at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:74)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:371)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:128)
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:262)
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:248)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195)
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:49)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:114)
    at org.springframework.batch.test.JobLauncherTestUtils.launchJob(JobLauncherTestUtils.java:151)
    at org.springframework.batch.test.JobLauncherTestUtils.launchJob(JobLauncherTestUtils.java:140)
    at com.hoge.foo.JobTest.testLaunchJob(JobTest.java:138)
    中略
Caused by: java.sql.BatchUpdateException: ORA-01461: LONG値はLONG列にのみバインドできます。

    at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:15000)
    at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:591)
    at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.ibatis.common.jdbc.logging.PreparedStatementLogProxy.invoke(PreparedStatementLogProxy.java:88)
    at $Proxy14.executeBatch(Unknown Source)
    at com.ibatis.sqlmap.engine.execution.SqlExecutor$Batch.executeBatchDetailed(SqlExecutor.java:642)
    at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeBatchDetailed(SqlExecutor.java:142)
    at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.executeBatchDetailed(SqlMapExecutorDelegate.java:775)
    at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.executeBatchDetailed(SqlMapSessionImpl.java:188)
    at org.springframework.batch.item.database.IbatisBatchItemWriter$1.doInSqlMapClient(IbatisBatchItemWriter.java:131)
    at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:209)
    ... 52 more

該当のソースコード

Job定義は
ReaderにてXMLファイルの一覧を取得し、Readで1件ずつファイル名をProcessorに引き渡し、
ProcessorにてXMLファイルをString文字列でAAAAクラスに格納、
Writer(org.springframework.batch.item.database.IbatisBatchItemWriter)を使用し、格納となっています。

package com.hoge.foo;
public class AAAA {
    private Integer id;
    private String  xmldata;
    //各セッター・ゲッター
}
SqlMap.xml
<sqlMap namespace="SqlMap_HOGE_TABLE">
 <insert id="insertForXMLTYPE" parameterClass="com.hoge.foo.AAAA">
 INSERT INTO HOGE_TABLE (ID,XML_DATA) VALUES(#id:DECIMAL#,#xmldata:OTHER#)
 </insert>
</sqlMap>

SqlMapConfig.xml
<sqlMapConfig>
    <settings useStatementNamespaces="true"/>
    <sqlMap resource="sqlmaps/SqlMap.xml"/>
</sqlMapConfig>

試したこと

ファイル自体の容量を小さくした場合に、正常にINSERTされることを確認しました。
org.springframework.jdbc.support.xml.Jdbc4SqlXmlHandlerをどうにかして、利用できれば、
と試してみましたが、組み込み方法がよくわからず、下記のように記載しましたが、エラーとなりました。

SqlMapConfig.xml
<sqlMapConfig>
    <settings useStatementNamespaces="true"/>
    <sqlMap resource="sqlmaps/SqlMap.xml"/>
    <typeHandler javaType="java.lang.String" callback="Jdbc4SqlXmlHandler"/>
</sqlMapConfig>

また、PrepareStatementを使用し、SQLXML型でINSERTができるのではないかと考え、
下記の実装を行ってみましたが、エラーが発生しました。

・フィールドにてデータソースを定義し、@Autowiredで注入
        private OracleDataSource ds;

        ・処理メソッド
        AAAA aaaa = new AAAA();
        OracleConnection conn = null;
        OraclePreparedStatement pre= null;
        try {
            conn = (OracleConnection) ds.getConnection();
            StringBuilder sql = new StringBuilder();
            sql.append("INSERT INTO HOGE_TABLE (ID,XML_DATA) VALUES (?,?)");
            pre =  (OraclePreparedStatement) conn.prepareStatement(sql.toString());
            int parameterIndex = 1;
            pre.setString(parameterIndex++, aaaa.getId());
            SQLXML xmlObject = conn.createSQLXML();
            xmlObject.setString(aaaa.getXmlData());
            pre.setSQLXML(parameterIndex++, xmlObject);

            pre.addBatch();
            pre.executeUpdate();

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            SFDBUtils.closeQuietly(conn, pre, null);
        }
データソースに@Autowiredを行う設定
<bean id="test.XMLDB" class="oracle.jdbc.pool.OracleDataSource">
    <property name="URL"             value="${XMLDB.jdbc.url}" />
</bean>
また、このデータソースでも同様に試しましたが、エラーが発生するのは変わらず。
<bean id="test.XMLDB" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="oracle.jdbc.OracleDriver" />
    <property name="url"             value="${XMLDB.url}" />
    <property name="username"        value="${XMLDB.username}" />
    <property name="password"        value="${XMLDB.password}" />
</bean>
発生したエラー
java.sql.SQLException: サポートされない機能です。
    at oracle.jdbc.driver.PhysicalConnection.createSQLXML(PhysicalConnection.java:17745)
    at com.hoge.foo.JobTest.testLaunchJob(JobTest.java:102)
    //省略

補足情報(言語/FW/ツール等のバージョンなど)

  • Java
    java version "1.6.0_24"
    Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
    Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, mixed mode)

  • Spring Batch
    spring-batch-2.1.6

  • Spring Beans
    spring-beans-2.5

  • Oracle
    Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
    PL/SQL Release 11.2.0.1.0 - Production
    CORE    11.2.0.1.0      Production
    TNS for Linux: Version 11.2.0.1.0 - Production
    NLSRTL Version 11.2.0.1.0 - Production

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

OTNの記事とクライアントのバグという記事がありました。
まず、怪しいのはクライアントのバグ説(バージョンが一致しているので)
http://www.projectgroup.info/tips/Oracle/errorcode/ORA01461.html

OTNの記事はXMLtypeの容量算定について
http://otn.oracle.co.jp/forum/thread.jspa?messageID=16001040

参考になりますでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/28 17:05

    早速の回答ありがとうございます。
    OracleClientのバグ説については、ojdbc6_g.jarを更新して、実施したところ変化はありませんでした。
    また、Oracle12c環境にてテスト同様に実施しましたが、変わらず・・・
    【Oracle】
    Oracle Database 12c SE 12.1.0.2.0

    キャンセル

  • 2016/10/28 17:21

    お役に立てず、申し訳ない。
    1点、気になるのは、

    >ojdbc6_g.jarを更新して、
    *_g.jarは、デバッグ機能付きのJDBCなので、
    通常のojdbc6.jarで、どう動くか、ですねぇ・・。

    キャンセル

0

さっぱりアプローチが変わるので別回答とします。

原点に立ち返って、登録したいXMLを分解して、
フィールドをそれぞれ適切に保存する、というのはダメですか?

分解したいXMLの形があるなら、
・ trangというツールでXMLからdtdを逆作成(XMLの定義が作成されます)
・ xjcコマンドでbeanを作成(javaのオブジェクトが作成されます。)
・ java内ではXMLファイルをinにして、JAXBライブラリで分解
という感じで、割と手軽にXML <-> bean変換できます。

beanを作ってしまえば、コードでは、
JAXBContext jc = JAXBContext.newInstance(VirtFirewall.class);
StringReader reader = new StringReader(xml);
Unmarshaller u = jc.createUnmarshaller();
return (前もって作ったBean) u.unmarshal(reader);

こんな書きっぷりでBeanにはざっくり変換できます。
お役に立てなかったので、ご参考までに・・。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/31 17:19

    別アプローチのご回答ありがとうございます。
    本件に関しては、XSDの変更の可能性があり、JAXB変換・テーブルカラムを変更し対応する方法よりは、丸ごとXMLデータを格納しておきたいと考えておりました。

    JAXBはSAX,StAXより変換が楽で便利ですよね!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.55%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る