1. 程式人生 > >mybatis 插入oracle xmltype型別的資料內容超過4000報錯

mybatis 插入oracle xmltype型別的資料內容超過4000報錯

資料庫表:

create table BOOK
(
  book_id    NUMBER not null,
  book_name  XMLTYPE,
  book_price NUMBER
)

JavaBean:

public class Book {
    private Integer bookId;

    private String bookName;

    private Integer bookPrice;

      get(),set().......
}

mapper.xml 
  <insert id="insert" parameterType="com.zfy.db.model.Book" >
    insert into BOOK (BOOK_ID, BOOK_PRICE, BOOK_NAME
      )
    values (#{bookId}, #{bookPrice,jdbcType=INTEGER}, #{bookName}
      )
  </insert>


JUNIT測試:插入操作

public String getXml() {
		File file = new File("E:\\test.xml");
		InputStream ios = null;
		StringBuffer xml = new StringBuffer();
		try {
			ios = new FileInputStream(file);
			byte[] b = new byte[(int) file.length()];
			for (int i = 0; i < b.length; i++) {
				b[i] = (byte) ios.read();
			}
			xml.append(new String(b));

		} catch (Exception e) {

		} finally {
			try {
				if (ios != null)
					ios.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return xml.toString();
	}

	
	//xmlType型別
	@Test
	public void  insertXMLTYPE() throws ParserConfigurationException, SAXException, IOException{
		Book book = new Book();
		book.setBookId(3);
		book.setBookName(getXml());
		book.setBookPrice(33);
	         session.insert("com.zfy.db.dao.BookMapper.insert",book);
		session.commit();
		session.close();
	}


報錯如下:

org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: java.sql.SQLException: ORA-01461: 僅能繫結要插入 LONG 列的 LONG 值


### The error may exist in com/zfy/db/mapping/BookMapper.xml
### The error may involve com.zfy.db.dao.BookMapper.insert-Inline
### The error occurred while setting parameters
### SQL: insert into BOOK (BOOK_ID, BOOK_PRICE, BOOK_NAME       )     values (?, ?, ?       )
### Cause: java.sql.SQLException: ORA-01461: 僅能繫結要插入 LONG 列的 LONG 值


at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:137)
at com.zfy.controller.test.ControllerTest.insertXMLTYPE(ControllerTest.java:358)
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 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
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: java.sql.SQLException: ORA-01461: 僅能繫結要插入 LONG 列的 LONG 值


at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:206)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:455)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:413)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:1034)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:194)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:953)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1222)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3387)
at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3488)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1374)
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 org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:55)
at sun.proxy.$Proxy11.execute(Unknown Source)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:41)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:66)
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 org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:59)
at sun.proxy.$Proxy9.update(Unknown Source)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:45)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:100)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:75)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:148)
... 26 more

現在兩種解決方法:

1、用JDBC ,但不適合JDNI資料來源

工具類:XmlTypeUtil.java

package com.zfy.com.util;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

import oracle.xml.parser.v2.DOMParser;

public class XmlTypeUtil {
	
	public static org.w3c.dom.Document getDocument(String str) throws Exception{
		if(getStr(str).equals("")){
			return null;
		}
		org.w3c.dom.Document doc=null;
		try{
			DOMParser parser = new DOMParser();
			parser.parse(getStringInputString(str));
			doc =parser.getDocument();			
		}catch(Exception e){
			e.printStackTrace();
			throw e;
		}
		return doc;
	}


	/**
	 * org.w3c.dom.Document -> org.dom4j.Document
	 * 
	 * @param doc
	 *            Document(org.w3c.dom.Document)
	 * @return Document
	 */
	public static org.dom4j.Document parse(org.w3c.dom.Document doc)
			throws Exception {
		if (doc == null) {
			return (null);
		}
		org.dom4j.io.DOMReader xmlReader = new org.dom4j.io.DOMReader();
		return (xmlReader.read(doc));
	}

	/**
	 * org.dom4j.Document -> org.w3c.dom.Document
	 * 
	 * @param doc
	 *            Document(org.dom4j.Document)
	 * @throws Exception
	 * @return Document
	 */
	public static org.w3c.dom.Document parse(org.dom4j.Document doc)
			throws Exception {
		if (doc == null) {
			return (null);
		}
		java.io.StringReader reader = new java.io.StringReader(doc.asXML());
		org.xml.sax.InputSource source = new org.xml.sax.InputSource(reader);
		javax.xml.parsers.DocumentBuilderFactory documentBuilderFactory = javax.xml.parsers.DocumentBuilderFactory
				.newInstance();
		javax.xml.parsers.DocumentBuilder documentBuilder = documentBuilderFactory
				.newDocumentBuilder();
		return (documentBuilder.parse(source));
	}
	
	public static String getStr(Object obj) {
		String s = obj == null ? "" : String.valueOf(obj);
		if (s.equals("null")) {
			return "";
		}
		return s;
	}
	
	public static InputStream getStringInputString(String str)
	throws UnsupportedEncodingException {
		InputStream f = new ByteArrayInputStream(getStr(str).getBytes("GBK"));
		return f;
}

}

JDBC插入一條xml超過4000字元的資料到資料庫
public void insertXmlContent(String fileId, String xmlContent) throws Exception {
		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = java.sql.DriverManager.getConnection("jdbc:oracle:thin:@192.168.1.252:1521:orcl","dsci","dsci");
		OraclePreparedStatement stmt = null;
		Document doc = XmlTypeUtil.getDocument(xmlContent);
		String sql = "insert into  dsc_pro_xml_t0d0(xml_content) values (?)";
		stmt = (OraclePreparedStatement) conn.prepareStatement(sql);
		XMLType xmlTypeContent = null;
		xmlTypeContent = XMLType.createXML(conn, doc);
		stmt.setObject(1, xmlTypeContent);
		stmt.executeUpdate();	
	}

方法二:使用臨時表的辦法實現(未測試),這種比較麻煩,但不用考慮資料來源問題

先建立一個臨時的表,其中的一個欄位是clob型別;
再將要寫入xmltype欄位的xml doc寫入這個臨時的clob型的欄位中;
最後insert into abc (id,xmldoc) values (abc_q.nextval , sys.xmlType.createXML((select content from 臨時表 where id=......)));