Java 将CLOB插入Oracle数据库
我的问题是:在使用Java 将CLOB插入Oracle数据库,java,oracle,jdbc,insert,clob,Java,Oracle,Jdbc,Insert,Clob,我的问题是:在使用CLOBs插入(或在查询中执行任何操作)时,如何避免ORA-01704:string literal过长错误 我想要一个这样的查询: INSERT ALL INTO mytable VALUES ('clob1') INTO mytable VALUES ('clob2') --some of these clobs are more than 4000 characters... INTO mytable VALUES ('clob3') SELECT *
CLOB
s插入(或在查询中执行任何操作)时,如何避免ORA-01704:string literal过长
错误
我想要一个这样的查询:
INSERT ALL
INTO mytable VALUES ('clob1')
INTO mytable VALUES ('clob2') --some of these clobs are more than 4000 characters...
INTO mytable VALUES ('clob3')
SELECT * FROM dual;
当我尝试使用实际值时,虽然我得到了ORA-01704:string literal太长
返回。这很明显,但是如何插入clob(或者使用clob执行任何语句)
我试过看这个,但我觉得它没有我想要的。我拥有的CLOB在一个列表中
,我反复遍历它们以做出声明。我的代码如下:
private void insertQueries(String tempTableName) throws FileNotFoundException, DataException, SQLException, IOException {
String preQuery = " into " + tempTableName + " values ('";
String postQuery = "')" + StringHelper.newline;
StringBuilder inserts = new StringBuilder("insert all" + StringHelper.newline);
List<String> readQueries = getDomoQueries();
for (String query : readQueries) {
inserts.append(preQuery).append(query).append(postQuery);
}
inserts.append("select * from dual;");
DatabaseController.getInstance().executeQuery(databaseConnectionURL, inserts.toString());
您需要使用绑定变量,而不是使用字符串连接构建SQL语句。从安全性、性能和健壮性的角度来看,这将是有益的,因为它将降低SQL注入攻击的风险,减少Oracle花费在SQL语句硬解析上的时间,并将消除字符串中存在导致生成无效SQL语句(即单引号)的特殊字符的可能性 我想你会想要像这样的东西
private void insertQueries(String tempTableName) throws FileNotFoundException, DataException, SQLException, IOException {
String preQuery = " into " + tempTableName + " values (?)" + StringHelper.newline;
StringBuilder inserts = new StringBuilder("insert all" + StringHelper.newline);
List<String> readQueries = getDomoQueries();
for (String query : readQueries) {
inserts.append(preQuery);
}
inserts.append("select * from dual");
Connection conn = ConnectionPool.getInstance().get(connection);
PreparedStatement pstmt = conn.prepareStatement(
inserts);
int i = 1;
for (String query : readQueries) {
Clob clob = CLOB.createTemporary(conn, false, oracle.sql.CLOB.DURATION_SESSION);
clob.setString(i, query);
pstmt.setClob(i, clob);
i = i + 1;
}
pstmt.executeUpdate();
}
private void insertquerys(String testablename)抛出FileNotFoundException、DataException、SQLException、IOException{
字符串preQuery=“into”+试探性名称+”值(?)+StringHelper.newline;
StringBuilder inserts=新建StringBuilder(“全部插入”+StringHelper.newline);
List readquerys=getdomoquerys();
for(字符串查询:readQueries){
insert.append(预查询);
}
插入。追加(“从双变量中选择*);
连接conn=ConnectionPool.getInstance().get(连接);
PreparedStatement pstmt=conn.prepareStatement(
插入);
int i=1;
for(字符串查询:readQueries){
Clob Clob=Clob.createTemporary(conn,false,oracle.sql.Clob.DURATION\u会话);
clob.setString(i,查询);
pstmt.setClob(i,clob);
i=i+1;
}
pstmt.executeUpdate();
}
您正朝着复杂的方向前进
对列表中的每个clob使用PreparedStatement和addBatch()
String sql = "insert into " + tempTableName + " values (?)";
PreparedStatement stmt = connection.prepareStatement(sql);
for (String query : readQueries) {
stmt.setCharacterStream(1, new StringReader(query), query.lenght());
stmt.addBatch();
}
stmt.exececuteBatch();
无需处理转义字符串,无需处理文本长度问题,无需创建临时CLOB。而且最有可能的速度和使用单个INSERT ALL语句一样快
如果您使用的是当前驱动程序(>10.2),那么我认为setCharacterStream()调用和创建读取器也不是必需的。一个简单的setString(1,查询)
很可能也能工作。BLOB(二进制大对象)和CLOB(字符大对象)是特殊的数据类型,可以以对象或文本的形式保存大块数据。Blob和Clob对象将对象的数据作为流持久化到数据库中
下面是一段代码示例:
public class TestDB {
public static void main(String[] args) {
try {
/** Loading the driver */
Class.forName("com.oracle.jdbc.Driver");
/** Getting Connection */
Connection con = DriverManager.getConnection("Driver URL","test","test");
PreparedStatement pstmt = con.prepareStatement("insert into Emp(id,name,description)values(?,?,?)");
pstmt.setInt(1,5);
pstmt.setString(2,"Das");
// Create a big CLOB value...AND inserting as a CLOB
StringBuffer sb = new StringBuffer(400000);
sb.append("This is the Example of CLOB ..");
String clobValue = sb.toString();
pstmt.setString(3, clobValue);
int i = pstmt.executeUpdate();
System.out.println("Done Inserted");
pstmt.close();
con.close();
// Retrive CLOB values
Connection con = DriverManager.getConnection("Driver URL","test","test");
PreparedStatement pstmt = con.prepareStatement("select * from Emp where id=5");
ResultSet rs = pstmt.executeQuery();
Reader instream = null;
int chunkSize;
if (rs.next()) {
String name = rs.getString("name");
java.sql.Clob clob = result.getClob("description")
StringBuffer sb1 = new StringBuffer();
chunkSize = ((oracle.sql.CLOB)clob).getChunkSize();
instream = clob.getCharacterStream();
BufferedReader in = new BufferedReader(instream);
String line = null;
while ((line = in.readLine()) != null) {
sb1.append(line);
}
if (in != null) {
in.close();
}
// this is the clob data converted into string
String clobdata = sb1.toString();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
从
您必须记住以下大数据输入模式的自动切换。
有三种输入模式:直接绑定、流绑定和LOB绑定
对于PL/SQL语句
setBytes和setBinary流方法对小于32767字节的数据使用直接绑定
setBytes和setBinaryStream方法对大于32766字节的数据使用LOB绑定
setString、setCharacterStream和SetAsciaStream方法对数据库字符集中小于32767字节的数据使用直接绑定
setString、setCharacterStream和SetAsciaStream方法对数据库字符集中大于32766字节的数据使用LOB绑定
oracle.jdbc.OraclePreparedStatement接口中的setBytesForBlob和setStringForClob方法对任何数据大小都使用LOB绑定
下面是将文件内容放入PLSQL过程的输入CLOB参数的示例:
public int fileToClob( FileItem uploadFileItem ) throws SQLException, IOException
{
//for using stmt.setStringForClob method, turn the file to a big String
FileItem item = uploadFileItem;
InputStream inputStream = item.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader( inputStream );
BufferedReader bufferedReader = new BufferedReader( inputStreamReader );
StringBuffer stringBuffer = new StringBuffer();
String line = null;
while((line = bufferedReader.readLine()) != null) { //Read till end
stringBuffer.append(line);
stringBuffer.append("\n");
}
String fileString = stringBuffer.toString();
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
item.delete();
OracleCallableStatement stmt;
String strFunction = "{ call p_file_to_clob( p_in_clob => ? )}";
stmt= (OracleCallableStatement)conn.prepareCall(strFunction);
try{
SasUtility servletUtility = sas.SasUtility.getInstance();
stmt.setStringForClob(1, fileString );
stmt.execute();
} finally {
stmt.close();
}
}
我喜欢使用java.sql.*包中的类,而不是oracle.*之类的东西。对我来说,这是一个简单的方法
Connection con = ...;
try (PreparedStatement pst = con.prepareStatement(
"insert into tbl (other_fld, clob_fld) values (?,?)", new String[]{"tbl_id"});
) {
Clob clob = con.createClob();
readIntoClob(clob, inputStream);
pst.setString(1, "other");
pst.setClob(2, clob);
pst.executeUpdate();
try (ResultSet rst = pst.getGeneratedKeys()) {
if (rst == null || !rst.next()) {
throw new Exception("error with getting auto-generated key");
}
id = rst.getBigDecimal(1);
}
当测试(当前的tomcat、jdbc)进入生产时停止工作(由于愚蠢的原因被困在Tomcat6中)。con.createClob()返回null的原因在该版本中未知,所以我不得不做这个双重判断(我花了很长时间才弄清楚,所以我在这里分享…)
为了完整起见,这里有
// Read data from an input stream and insert it in to the clob column
private static void readIntoClob(Clob clob, InputStream stream) {
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream))) {
char[] buffer = new char[CHUNK_BUFFER_SIZE];
int charsRead;
try (Writer wr = clob.setCharacterStream(1L)) {
// Loop for reading of chunk of data and then write into the clob.
while ((charsRead = bufferedReader.read(buffer)) != -1) {
wr.write(buffer, 0, charsRead);
}
} catch (SQLException | IOException ex) {
...
}
}
}
这是从其他地方来的,谢谢。在上查看一些与CLOB相关的样本 您是否尝试过使用
PreparedStatement
及其setClob()
方法,而不是动态SQL和使用字符串文本构建insert语句?我认为这应该是可行的,除了setClob
方法采用clob而不是字符串。在另一个问题中,它显示了clob的创建是这样的:oracle.sql.clob.createTemporary(connection,false,oracle.sql.clob.DURATION\u SESSION)
是否正确?@kentcdoffics-我相信是的(我目前没有Java开发环境进行测试),您也可以对Oracle CLOB列执行setString()。OracleJDBC驱动程序足够智能,可以执行转换。我认为这非常有效。我得到一个ORA-00911:无效字符
,这并不奇怪。我环顾四周,有没有什么简单的方法可以从PreparedStatement
中获取查询,这样我就可以看出哪里出了问题?@JustinCave,我刚刚为Clob编辑了你的答案,但我不确定是否要执行Clob.setString(I,query)代码>或clob.setString(1,查询)代码>…感谢您的回复。下次,请使用逻辑缩进方案格式化代码。这次我将为你编辑你的帖子。(提示:如果您的代码除了功能性之外还很漂亮,那么您将获得更多的支持票。)
try (PreparedStatement pst = con.prepareStatement(
"insert into tbl (other_fld) values (?)", new String[]{"tbl_id"});
PreparedStatement getClob= con.prepareStatement(
"select clob_fld from tbl where tbl_id = ? for update");
) {
Clob clob = con.createClob();
readIntoClob(clob, inputStream);
pst.setString(1, "other");
pst.executeUpdate();
try (ResultSet rst = pst.getGeneratedKeys()) {
if (rst == null || !rst.next()) {
throw new Exception("error with getting auto-generated key");
}
id = rst.getBigDecimal(1);
}
// fetch back fresh record, with the Clob
getClob.setBigDecimal(1, id);
getClob.execute();
try (ResultSet rst = getClob.getResultSet()) {
if (rst == null || !rst.next()) {
throw new Exception("error with fetching back clob");
}
Clob c = rst.getClob(1);
// Fill in data
readIntoClob(c, stream);
// that's all
}
} catch (SQLException) {
...
}
// Read data from an input stream and insert it in to the clob column
private static void readIntoClob(Clob clob, InputStream stream) {
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream))) {
char[] buffer = new char[CHUNK_BUFFER_SIZE];
int charsRead;
try (Writer wr = clob.setCharacterStream(1L)) {
// Loop for reading of chunk of data and then write into the clob.
while ((charsRead = bufferedReader.read(buffer)) != -1) {
wr.write(buffer, 0, charsRead);
}
} catch (SQLException | IOException ex) {
...
}
}
}