HibernateException: IOException occurred reading text + java.io.IOException: 違反協議: [14,0]

環境:

Hibernate 4.2.7.SP1

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0  64bit production

OJDBC7:12.1.0.1


報錯:

數據:向數據庫中插入一條數據,數據中某一個字段是CLOB類型,長度爲4193個字符

報錯異常:

2020-05-20 11:47:23,950 [qtp1288052401-61] c.p.p.m.d.ModelDao ERROR IOException occurred reading text
org.hibernate.HibernateException: IOException occurred reading text
	at org.hibernate.type.descriptor.java.DataHelper.extractString(DataHelper.java:94) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.type.descriptor.java.DataHelper.extractString(DataHelper.java:280) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.type.descriptor.java.StringTypeDescriptor.wrap(StringTypeDescriptor.java:89) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.type.descriptor.java.StringTypeDescriptor.wrap(StringTypeDescriptor.java:39) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.type.descriptor.sql.ClobTypeDescriptor$1.doExtract(ClobTypeDescriptor.java:60) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:64) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:261) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:247) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:332) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2926) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1673) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1605) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.loader.Loader.getRow(Loader.java:1505) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:713

 

Caused by: java.io.IOException: 違反協議: [ 14, 0, ]
	at oracle.jdbc.driver.OracleClobReader.needChars(OracleClobReader.java:264) ~[ojdbc7-12.1.0.1.jar:12.1.0.1.0]
	at oracle.jdbc.driver.OracleClobReader.read(OracleClobReader.java:195) ~[ojdbc7-12.1.0.1.jar:12.1.0.1.0]
	at org.hibernate.type.descriptor.java.DataHelper.extractString(DataHelper.java:86) ~[hibernate-core-4.2.7.SP1.jar:4.2.7.SP1]
	... 119 more
Caused by: java.sql.SQLException: 違反協議: [ 14, 0, ]
	at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:669) ~[ojdbc7-12.1.0.1.jar:12.1.0.1.0]
	at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:249) ~[ojdbc7-12.1.0.1.jar:12.1.0.1.0]
	at oracle.jdbc.driver.T4C8TTIClob.read(T4C8TTIClob.java:245) ~[ojdbc7-12.1.0.1.jar:12.1.0.1.0]
	at oracle.jdbc.driver.T4CConnection.getChars(T4CConnection.java:3901) ~[ojdbc7-12.1.0.1.jar:12.1.0.1.0]
	at oracle.sql.CLOB.getChars(CLOB.java:517) ~[ojdbc7-12.1.0.1.jar:12.1.0.1.0]
	at oracle.jdbc.driver.OracleClobReader.needChars(OracleClobReader.java:245) ~[ojdbc7-12.1.0.1.jar:12.1.0.1.0]

源碼分析:

public static String extractString(Reader reader, int lengthHint) {
		// read the Reader contents into a buffer and return the complete string
		final int bufferSize = getSuggestedBufferSize( lengthHint );
		final StringBuilder stringBuilder = new StringBuilder( bufferSize );
		try {
			char[] buffer = new char[bufferSize];
			while (true) {
				int amountRead = reader.read( buffer, 0, bufferSize );
				if ( amountRead == -1 ) {
					break;
				}
				stringBuilder.append( buffer, 0, amountRead );
			}
		}
		catch ( IOException ioe ) {
			throw new HibernateException( "IOException occurred reading text", ioe );
		}
		finally {
			try {
				reader.close();
			}
			catch (IOException e) {
				LOG.unableToCloseStream( e );
			}
		}
		return stringBuilder.toString();
	}

調試追蹤到Hibernate在讀取CLOB字段轉換爲String數據類型時,在read方法處拋出異常:int amountRead = reader.read( buffer, 0, bufferSize );

繼續往裏追蹤,發現,read方法調用的是ojdbc7驅動中的OracleClobReader.read(char[] var1, int var2, int var3)方法:

public int read(char[] var1, int var2, int var3) throws IOException {
        this.ensureOpen();
        int var5 = var2 + Math.min(var3, var1.length - var2);
        if (!this.needChars(var5 - var2)) {
            return -1;
        } else {
            int var4;
            for(var4 = var2 + this.writeChars(var1, var2, var5 - var2); var4 < var5 && this.needChars(var5 - var4); var4 += this.writeChars(var1, var4, var5 - var4)) {
            }

            return var4 - var2;
        }
    }

繼續追蹤,發現是在調用 needChars(int var1) 方法時拋出異常:

protected boolean needChars(int var1) throws IOException {
        this.ensureOpen();
        if (this.pos >= this.count) {
            if (!this.endOfStream) {
                try {
                    if (var1 > this.currentBufferSize) {
                        this.currentBufferSize = Math.max(var1, this.initialBufferSize);
                        PhysicalConnection var2 = (PhysicalConnection)this.clob.getInternalConnection();
                        synchronized(var2) {
                            this.resizableBuffer = var2.getCharBuffer(this.currentBufferSize);
                        }
                    }

                    int var7 = this.currentBufferSize;
                    if (this.maxPosition - this.lobOffset < (long)this.currentBufferSize) {
                        var7 = (int)(this.maxPosition - this.lobOffset);
                    }

                    this.count = this.clob.getChars(this.lobOffset, var7, this.resizableBuffer);
                    if (this.count < this.currentBufferSize) {
                        this.endOfStream = true;
                    }

                    if (this.count > 0) {
                        this.pos = 0;
                        this.lobOffset += (long)this.count;
                        if (this.lobOffset >= this.maxPosition) {
                            this.endOfStream = true;
                        }

                        return true;
                    }
                } catch (SQLException var6) {
                    IOException var3 = DatabaseError.createIOException(var6);
                    var3.fillInStackTrace();
                    throw var3;
                }
            }

            return false;
        } else {
            return true;
        }
    }

經過對邏輯分析與調試,發現4193長度的字符串調用getInternalConnection會拋出異常,但是加大了了字符串長度到8193後,異常不再拋出,於是懷疑是OJDBC7這個版本的bug,升級到OJDBC7:12.1.0.2後,問題得到解決


疑問:

至於12.1.0.1版本字符串長度爲4193時,調用getInternalConnection()方法後會拋出異常的原因還未深究,感興趣的同學可以瞭解一下源碼,看一下具體問題出現的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章