2012-06-28 114 views
0

獲取二進制流時收到以下異常。IOException:流已關閉Hibernate MS SQL JDBC4

java.io.IOException: The stream is closed. 
at com.microsoft.sqlserver.jdbc.BaseInputStream.checkClosed(SimpleInputStream.java:93) 
at com.microsoft.sqlserver.jdbc.PLPInputStream.read(PLPInputStream.java:237) 
at au.gov.vic.doi.tp.service.binary.dao.BinaryDAOImplTest.retrieveBinary(BinaryDAOImplTest.java:102) 

我正在使用:Hibernate 4.1.1,MS SQL Server 2008和最新的MS SQL JDBC4驅動程序。 我使用以下自定義映射類型'BlobToStreamUserType'將SQL Blob(varchar(max))映射到InputStream。 Hibernate似乎沒有提供將SQL BLOB映射到Java InputStream的類型,但MaterializedBlobType只將SQL BLOB映射到Java byte []。

我正在使用'rs.getBinaryStream'返回一個真正的二進制流而不是緩衝在內存中的流,原因是我們有大圖像,如果多個用戶同時訪問會導致內存問題。

據微軟

的Microsoft驅動程序遵循JDBC規範相對於getBinaryStream => 注意:返回流中的所有數據必須得到任何>其他列的值之前被讀取。下一次調用getter方法會隱式關閉流。此外,當調用InputStream.available方法時,如果數據>可用或不可用,則stream>可能會返回0。

所以getBinaryStream被設計爲返回一個真正的字節流。我們返回一個真正的字節流,它不會緩衝在內存中,它是一個從服務器響應中直接讀取的流。您不能關閉contentDataResultSet,直到您爲我們的實現獲取所有字節。

我試着將hibernate屬性'hibernate.jdbc.use_streams_for_binary'設置爲true和false,但這沒什麼區別。

這是我的代碼:

圖像實體類顯示映射到自定義用戶類型。

import java.io.InputStream; 
    import java.util.Date; 
    import javax.persistence.Column; 
    import javax.persistence.Entity; 
    import javax.persistence.GeneratedValue; 
    import javax.persistence.Id; 
    import javax.persistence.Table; 
    import org.hibernate.annotations.DynamicInsert; 
    import org.hibernate.annotations.DynamicUpdate; 
    import org.hibernate.annotations.GenericGenerator; 
    import org.hibernate.annotations.Type; 
    import com.google.common.base.Objects; 

    @Entity 
    @DynamicInsert(false) 
    @DynamicUpdate(false) 
    @Table(name = "Binary") 
    public class Binary 
    { 
    ......... 
    @Lob 
    @Column(name = "image") 
    @Type(type = "my.package.BlobToStreamUserType") 
    public InputStream getImageStream() 
    { 
     return this.imageStream; 
    } 
    } 

這裏是我的自定義映射類型:

public class BlobToStreamUserType implements UserType 
{ 

public int[] sqlTypes() 
{ 
    return new int[] 
    { Types.BLOB }; 
} 

public Class returnedClass() 
{ 
    return InputStream.class; 
} 

public Object nullSafeGet(final ResultSet rs, final String[] names, final SessionImplementor session, 
     final Object owner) throws HibernateException, SQLException 
{ 
    return rs.getBinaryStream(names[0]); 
} 

public void nullSafeSet(final PreparedStatement st, final Object value, final int index, 
     final SessionImplementor session) throws HibernateException, SQLException 
{ 

    if (value != null) 
    { 
     if (!InputStream.class.isAssignableFrom(value.getClass())) 
     { 
      throw new HibernateException(value.getClass().toString() + " cannot be cast to a java.IO.InputStream"); 
     } 
     InputStream inStream = (InputStream) value; 
     st.setBinaryStream(index, inStream); 
    } 
    else 
    { 
     st.setBytes(index, null); 
    } 
} 

public boolean equals(final Object x, final Object y) throws HibernateException 
{ 
    return ObjectUtils.equals(x, y); 
} 

public int hashCode(final Object x) throws HibernateException 
{ 
    assert (x != null); 
    return x.hashCode(); 
} 

public Object deepCopy(final Object value) throws HibernateException 
{ 
    return value; 
} 

public boolean isMutable() 
{ 
    return false; 
} 

public Object replace(final Object original, final Object target, final Object owner) throws HibernateException 
{ 
    return original; 
} 

public Serializable disassemble(final Object value) throws HibernateException 
{ 
    //disassemble() is only called when caching the data in the second-level cache 
    // also safe for mutable objects 
    throw new UnsupportedOperationException("Not supported yet."); 
} 

public Object assemble(final Serializable cached, final Object owner) throws HibernateException 
{ 
    throw new UnsupportedOperationException("Not supported yet."); 
} 

}

,這裏是我的DAO檢索圖像流

public class BinaryDAOImpl extends AbstractSpringHibernateDAO implements BinaryDAO 
{ 

public Binary getBinary(final String amsAssetId, final String assetMaintainer, final String variant, 
     final Integer sequence) throws GetException 
{ 

    try 
    { 
     Query query = super.getSession().createQuery(
       "from Binary bin where bin.amsAssetId = :amsAssetId and bin.assetMaintainer = :assetMaintainer " 
         + "and bin.variant = :variant and bin.sequence = :sequence"); 
     query.setParameter("amsAssetId", amsAssetId); 
     query.setParameter("assetMaintainer", assetMaintainer); 
     query.setParameter("variant", variant); 
     query.setParameter("sequence", sequence); 
     return query.uniqueResult(); 
    } 

鈮以下解決方法休眠繞過並直接從結果集作品中檢索流,並允許我無需讀取流例外。不過,我寧願使用休眠映射來檢索一個真正的二進制流。

修改DAO方法

public Binary getBinary(final String amsAssetId, final String assetMaintainer, final String variant, 
     final Integer sequence) throws GetException 
{ 
    try 
    { 
     Query query = super.getSession().createQuery(
       "from Binary bin where bin.amsAssetId = :amsAssetId and bin.assetMaintainer = :assetMaintainer " 
         + "and bin.variant = :variant and bin.sequence = :sequence"); 
     query.setParameter("amsAssetId", amsAssetId); 
     query.setParameter("assetMaintainer", assetMaintainer); 
     query.setParameter("variant", variant); 
     query.setParameter("sequence", sequence); 
     Binary binary = (Binary) query.uniqueResult(); 

     final String id = binary.getId(); 

     // Necessary until Hibernate supports InputStream mapping 
     binary.setImageStream(getSession().doReturningWork(new ReturningWork<InputStream>() 
     { 
         public InputStream execute(final Connection connection) throws SQLException 
         { 
          PreparedStatement statement = connection.prepareStatement("select image from Binary where id=?", 
            ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); 

          statement.setString(1, id); 

          ResultSet resultSet = statement.executeQuery(); 

          return (resultSet.first() ? resultSet.getBinaryStream(1) : null); 
         } 
        })); 

     return binary; 

    } 

回答

0

你試過標記類型作爲一個LOB?

@Lob 
@Column(name = "image") 
@Type(type = "my.package.BlobToStreamUserType") 
Blob blob; 

public Blob getBlob(){ 
    return blob; 
} 

而當你需要使用流?

  final InputStream is; 
    try { 
     is = blob.getBinaryStream(); 
        //do some work 
      } 

這將有助於瞭解你定義自己的類型之前,可以簡單地得到一個斑點 。

相關問題