经过测试:JAVA存取PostgreSQL的bytea类型均存在内存的限制问题(存取的数据过大会出现out of memory内存溢出的问题),EnterpriseDB对此做了优化。
取PostgreSQL中的bytea,并存储到硬盘上.
/** * @author Liu Yuanyuan */ private void getBytea { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { String driver = "org.postgresql.Driver"; String url = "jdbc:postgresql://" + "127.0.0.1" + ":" + "5866" + "/" + "db1"; Class.forName(driver); System.out.println("find class"); conn = DriverManager.getConnection(url, "lyy", "lyy"); System.out.println("connected"); stmt = conn.createStatement(); String sql = "select obj from lyy.rawtable2 where id = 1"; rs = stmt.executeQuery(sql); System.out.println("sql=" + sql); while (rs.next()) { System.out.println(rs.getMetaData().getColumnTypeName(1)); OutputStream ops = null; InputStream ips = null; File file = new File("e:" + File.separator + “binary”); try { ips = rs.getBinaryStream(1); byte[] buffer = new byte[ips.available()];//or other value like 1024 ops = new FileOutputStream(file); for (int i; (i = ips.read(buffer)) > 0;) { ops.write(buffer, 0, i); ops.flush(); } } catch (Exception ex) { ex.printStackTrace(System.out); } finally { ips.close(); ops.close(); } } } catch (Exception ex) { ex.printStackTrace(System.out); } finally { try { If(rs!=null) rs.close(); if(stmt!=null) stmt.close(); if(conn!=null) conn.close(); } catch (SQLException ex) { ex.printStackTrace(System.out); } } }
向bytea直接插入二进制文件
Private void insertByteaByBase64() { String driver = "org.postgresql.Driver"; String url = "jdbc:postgresql://" + "127.0.0.1" + ":" + "5432" + "/" + "postgres"; Connection conn = null; PreparedStatement ps = null; ResultSet st = null; try { Class.forName(driver); System.out.println("success find class"); conn = DriverManager.getConnection(url, "postgres", "pg"); System.out.println("success connect"); String sql = "insert into blobtable(id,obj) values(?,?)"; ps = conn.prepareStatement(sql); String fpath = “d:”+File. Separator + “image.jpg”; File file = new File(fpath); InputStream ips = new FileInputStream(file); ps.setInt(1, 400); ps.setBinaryStream(2, ips, file.length()); ps.executeUpdate(); System.out.println("insert"); } catch (Exception ex) { ex.printStackTrace(System.out); } finally { try { if(ps!=null) ps.close(); if(conn!= null) conn.close(); } catch (SQLException ex) { ex.printStackTrace(System.out); }} }
通过base64向bytea插入二进制文件
Private void insertByteaByBase64() { String driver = "org.postgresql.Driver"; String url = "jdbc:postgresql://" + "127.0.0.1" + ":" + "5432" + "/" + "postgres"; Connection conn = null; PreparedStatement ps = null; ResultSet st = null; try { Class.forName(driver); System.out.println("success find class"); conn = DriverManager.getConnection(url, "postgres", "pg"); System.out.println("success connect"); byte[] b = ByteaClass.getBytes();//得到数组byte[] System.out.println("Length = " + b.length); String s = Base64.encodeBytes(b, 0, b.length); System.out.println("s = " + s.length()); String sql = "insert into blobtable(id,obj) values(?,?)"; String c = "decode(\'" + s + "\',\'base64\')"; sql = sql.replace("?,?", "?," + c); System.out.println("sql = " + sql); ps = conn.prepareStatement(sql); ps.setInt(1, 400); ps.executeUpdate(); System.out.println("insert"); } catch (Exception ex) { ex.printStackTrace(System.out); } finally { try { if(ps!=null) ps.close(); if(conn!= null) conn.close(); } catch (SQLException ex) { ex.printStackTrace(System.out); } } }
常见错误1:setBinaryStream(,,int/long)参数类型异常
错误信息:Exception in thread "Thread-3" java.lang.AbstractMethodError: org.postgresql.jdbc3g.Jdbc3gPreparedStatement.setBinaryStream(ILjava/io/InputStream;J)V
错误原因:
ppstmt2.setBinaryStream(k, new FileInputStream(file),file.length());
file.length()是long型,postgresql-9.2-1002.jdbc3.jar仅支持setBinaryStream(,,int);
若不改变Jar包,可以强制转换为int,ppstmt2.setBinaryStream(k, new FileInputStream(file),(int)file.length());
若不强制转化为int,可以换jar包为postgresql-9.2-1003.jdbc4.jar,该jar包支持
setBinaryStream(,,int)和setBinaryStream(,,long)
参考资料:
PostgreSQL的版本介绍和jar下载: http://jdbc.postgresql.org/download.html
JDBC3statement的介绍:
http://jdbc.postgresql.org/development/privateapi/org/postgresql/jdbc3/AbstractJdbc3Statement.html#setBinaryStream(java.lang.String, java.io.InputStream, int)
JDBC4statement的详细介绍尚未推出。
常见错误2:无法为preparedStatement绑定参数setBinaryStream(,,int/long)
错误信息:
org.postgresql.util.PSQLException: Unable to bind parameter values for statement.
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:275)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:555
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:417)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:410)
JDBC源代码:
http://www.java2s.com/Open-Source/Java/Database-JDBC-Connection-Pool/postgresql/org/postgresql/core/v3/QueryExecutorImpl.java.htm
try { handler = sendQueryPreamble(handler, flags); sendQuery((V3Query)query, (V3ParameterList)parameters, maxRows, fetchSize, flags); sendSync(); processResults(handler, flags); } catch (PGBindException se) { // There are three causes of this error, an // invalid total Bind message length, a // BinaryStream that cannot provide the amount // of data claimed by the length arugment, and // a BinaryStream that throws an Exception // when reading. // // We simply do not send the Execute message // so we can just continue on as if nothing // has happened. Perhaps we need to // introduce an error here to force the // caller to rollback if there is a // transaction in progress? // sendSync(); processResults(handler, flags); handler.handleError(new PSQLException(GT.tr("Unable to bind parameter values for statement."), PSQLState.INVALID_PARAMETER_VALUE, se.getIOException())); }