从数据库中获取Blob"无效的事务句柄"

时间:2014-08-21 07:36:44

标签: spring-mvc firebird c3p0 jdbctemplate jaybird

我从数据库中获取结果时遇到问题。我正在使用firebird,c3p0,JDBCTemplate,SpringMVC。

public class InvoiceDaoImpl implements InvoiceDao {
...
    public Invoice getInvoice(int id) {
    List<Invoice> invoice = new ArrayList<Invoice>();
    String sql = "SELECT ID,FILENAME, FILEBODY FROM T_FILES WHERE id=" + id;
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    invoice = jdbcTemplate.query(sql, new InvoiceRowMapper());
    return invoice.get(0);
}....}    

二手型号:

public class Invoice {  
private int ID;
private Blob FILEBODY;
private String FILENAME;
getters and setters ...
}

RowMapper和Extractor是标准的。

在JSP中我得到一个FileStream并返回文件下载:

@RequestMapping("admin/file/GetFile/{id}")
public void invoiceGetFile(@PathVariable("id") Integer id, HttpServletResponse response) {

    Invoice invoice = invoiceService.getInvoice(id);
    try {
        response.setHeader("Content-Disposition", "inline;filename=\"" + invoice.getFILENAME() + "\"");
        OutputStream out = response.getOutputStream();
        response.setContentType("application/x-ms-excel");
        IOUtils.copy(invoice.getFILEBODY().getBinaryStream(), out);
        out.flush();
        out.close();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

catalina.out中:

datasource.DataSourceTransactionManager - Releasing JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@566b1836] after transaction
http-nio-8443-exec-29 DEBUG datasource.DataSourceUtils - Returning JDBC Connection to DataSource
http-nio-8443-exec-29 DEBUG resourcepool.BasicResourcePool - trace com.mchange.v2.resourcepool.BasicResourcePool@4d2dbc65 [managed: 2, unused: 1, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@4ca5c225)
org.firebirdsql.jdbc.FBSQLException: GDS Exception. 335544332. 
**invalid transaction handle (expecting explicit transaction start)**
at org.firebirdsql.jdbc.FBBlobInputStream.<init>(FBBlobInputStream.java:38)
at org.firebirdsql.jdbc.FBBlob.getBinaryStream(FBBlob.java:404)

我不明白为什么在使用SELECT时需要使用事务处理,而不是UPDATE或INSERT?

1 个答案:

答案 0 :(得分:2)

Firebird(以及JDBC)在事务中执行所有,因为事务决定了数据的可见性。

在这种特定情况下,select查询是在事务中执行的(可能是自动提交),但blob访问是在事务提交后完成的。

这会触发此特定异常,因为Jaybird知道它需要一个事务来检索blob,但即使Jaybird有一个新事务访问blob也无法工作,因为blob句柄仅在查询blob的事务中有效处理

您需要禁用自动提交,只需在检索blob之后提交(通过它的外观需要对DAO进行大量更改),或者您的行映射器需要显式加载blob(例如转换为字节数组)。

另一个选择是确保使用可保持的结果集执行此查询(在这种情况下,Jaybird会将blob实现为Blob实例中的字节数组),但我不确定{{1允许您指定使用可保持的结果集。