asa*_*n74 31 java oracle blob jdbc clob
当我使用jdbc瘦驱动程序搜索Web以将BLOB插入Oracle数据库时,大多数网页都建议采用三步法:
empty_blob()值.for update.这对我来说很好,这是一个例子:
Connection oracleConnection = ...
byte[] testArray = ...
PreparedStatement ps = oracleConnection.prepareStatement(
"insert into test (id, blobfield) values(?, empty_blob())");
ps.setInt(1, 100);
ps.executeUpdate();
ps.close();
ps = oracleConnection.prepareStatement(
"select blobfield from test where id = ? for update");
ps.setInt(1, 100);
OracleResultSet rs = (OracleResultSet) ps.executeQuery();
if (rs.next()) {
BLOB blob = (BLOB) rs.getBLOB(1);
OutputStream outputStream = blob.setBinaryStream(0L);
InputStream inputStream = new ByteArrayInputStream(testArray);
byte[] buffer = new byte[blob.getBufferSize()];
int byteread = 0;
while ((byteread = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, byteread);
}
outputStream.close();
inputStream.close();
}
Run Code Online (Sandbox Code Playgroud)
有一些网页作者建议使用更简单的一步解决方案.此解决方案的先前示例:
Connection oracleConnection = ...
byte[] testArray = ...
PreparedStatement ps = oracleConnection.prepareStatement(
"insert into test(id, blobfield) values(?, ?)");
BLOB blob = BLOB.createTemporary(oracleConnection, false, BLOB.DURATION_SESSION);
OutputStream outputStream = blob.setBinaryStream(0L);
InputStream inputStream = new ByteArrayInputStream(testArray);
byte[] buffer = new byte[blob.getBufferSize()];
int byteread = 0;
while ((byteread = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, byteread);
}
outputStream.close();
inputStream.close();
ps.setInt(1, 100);
ps.setBlob(2, blob);
ps.executeUpdate();
ps.close();
Run Code Online (Sandbox Code Playgroud)
第二个代码更容易,所以我的问题是:第一个(流行)解决方案的重点是什么?是否存在某种约束(Oracle服务器版本号,jdbc驱动程序版本,blob的大小......)?第一种解决方案更好(速度,内存消耗......)?没有使用更简单的第二种方法的任何理由?
完全相同的问题适用于CLOB字段.
Mr.*_* 安宇 11
您在第一种情况下提到的更新方法可以使用纯JDBC代码重写,从而减少您对特定于Oracle的类的依赖性.如果您的应用需要与数据库无关,这可能会有所帮助.
public static void updateBlobColumn(Connection con, String table, String blobColumn, byte[] inputBytes, String idColumn, Long id) throws SQLException {
PreparedStatement pStmt = null;
ResultSet rs = null;
try {
String sql =
" SELECT " + blobColumn +
" FROM " + table +
" WHERE " + idColumn + " = ? " +
" FOR UPDATE";
pStmt = con.prepareStatement(sql,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
pStmt.setLong(1, id);
rs = pStmt.executeQuery();
if (rs.next()) {
Blob blob = rs.getBlob(blobColumn);
blob.truncate(0);
blob.setBytes(1, inputBytes);
rs.updateBlob(blobColumn, blob);
rs.updateRow();
}
}
finally {
if(rs != null) rs.close();
if(pStmt != null) pStmt.close();
}
}
Run Code Online (Sandbox Code Playgroud)
对于MSSQL,我理解锁定语法是不同的:
String sql =
" SELECT " + blobColumn +
" FROM " + table + " WITH (rowlock, updlock) " +
" WHERE " + idColumn + " = ? "
Run Code Online (Sandbox Code Playgroud)
小智 7
Oracle DBA的另一种观点.当Sun设计JDBC标准(1.0,2.0,3.0,4.0)时,他们的工作非常糟糕.BLOB代表大型物体,因此它可能非常大.它是无法存储在JVM堆中的东西.Oracle认为BLOB与文件句柄类似(事实上它们称之为"lob定位器").LOBS不能通过构造函数创建,也不是Java对象.另外LOB定位器(oracle.sql.BLOB)不能通过构造函数创建 - 它们必须在DB端创建.在Oracle中,有两种方法可以创建LOB.
DBMS_LOB.CREATETEMPORATY - 在这种情况下返回的定位符指向临时表空间.针对此定位器的所有写入/读取将通过网络发送到DB服务器.JVM堆中没有存储任何内容.
调用EMPTY_BLOB函数.插入T1(名称,文件)值("a.avi",EMPTY_BLOB())返回文件?在这种情况下,返回的lob定位器指向数据表空间.针对此定位器的所有写入/读取将通过网络发送到DB服务器.通过写入重做日志来"保护"所有写入.JVM堆中没有存储任何内容.JDBC标准(1.0,2.0)不支持返回子句,因此您可以在互联网上找到许多人们建议采用两个步骤的示例:"INSERT ...; SELECT ... FOR UPDATE;"
Oracle lobs必须与某些数据库连接相关联,当数据库连接丢失/关闭/(或"提交")时,不能使用它们.它们不能从一个连接传递到另一个连接.
您的第二个示例可以工作,但如果数据从临时表空间进入数据表空间,则需要进行过多的复制.
Oracle服务器的LOB处理非常差,并且可能会遇到严重的性能问题(例如,大量过度使用重做日志),因此第一种解决方案可能是解决这些问题的方法.
我建议尝试这两种方法.如果您有一个称职的DBA,他们可能会建议哪种方法对服务器的影响最小.
JDBC的一个有趣之处在于,您可以相当积极地升级到最新的驱动程序并使用JDBC 4.0功能.oracle JDBC驱动程序将与较旧的数据库版本一起使用,因此您可以对10g数据库使用11g品牌JDBC驱动程序.Oracle数据库11g JDBC有两种形式:Java 5的ojdbc5.jar(即JDK 1.5)和Java 6的ojdbc6.jar(即JDK 1.6).ojdbc6.jar支持新的JDBC 4.0规范.
使用较新的drivers/jdbc 4.0,您可以从连接对象创建Blob和Clobs:
Blob aBlob = con.createBlob();
int numWritten = aBlob.setBytes(1, val);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
42618 次 |
| 最近记录: |