配色: 字号:
JavaWeb使用JDBC处理Oracle大数据
2016-08-30 | 阅:  转:  |  分享 
  
JavaWeb使用JDBC处理Oracle大数据



一、Oracle中大数据处理



在Oracle中,LOB(LargeObject,大型对象)类型的字段现在用得越来越多了。因为这种类型的字段,容量大(最多能容纳4GB的数据),且一个表中可以有多个这种类型的字段,很灵活,适用于数据量非常大的业务领域(如图象、档案等)。



LOB类型分为BLOB和CLOB两种:BLOB即二进制大型对象(BinaryLargeObject),适用于存贮非文本的字节流数据(如程序、图象、影音等)。而CLOB,即字符型大型对象(CharacterLargeObject),则与字符集相关,适于存贮文本型的数据(如历史档案、大部头著作等)。



二、搭建测试环境



2.1、建立两个测试用的数据库表



建表SQL语句为:



1CREATETABLETEST_CLOB(IDNUMBER(3),CLOBCOLCLOB)

2

3CREATETABLETEST_BLOB(IDNUMBER(3),BLOBCOLBLOB)

2.2、搭建测试项目架构







2.3、编写db.properties配置文件



1oracleDb_Driver=oracle.jdbc.driver.OracleDriver

2oracleDb_Url=jdbc:oracle:thin:@localhost:1521:GACL

3oracleDb_UserName=GACL_XDP

4oracleDb_Password=P

2.4、编写JdbcUtils工具类



复制代码

1packageme.gacl.utils;

2

3importjava.io.InputStream;

4importjava.sql.Connection;

5importjava.sql.DriverManager;

6importjava.sql.ResultSet;

7importjava.sql.SQLException;

8importjava.sql.Statement;

9importjava.util.Properties;

10

11publicclassJdbcUtils{

12

13privatestaticStringoracleDb_Driver=null;

14privatestaticStringoracleDb_Url=null;

15privatestaticStringoracleDb_UserName=null;

16privatestaticStringoracleDb_Password=null;

17

18static{

19try{

20//读取db.properties文件中的数据库连接信息

21InputStreamin=JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");

22Propertiesprop=newProperties();

23prop.load(in);

24

25//获取数据库连接驱动

26oracleDb_Driver=prop.getProperty("oracleDb_Driver");

27//获取数据库连接URL地址

28oracleDb_Url=prop.getProperty("oracleDb_Url");

29//获取数据库连接用户名

30oracleDb_UserName=prop.getProperty("oracleDb_UserName");

31//获取数据库连接密码

32oracleDb_Password=prop.getProperty("oracleDb_Password");

33

34//加载数据库驱动

35Class.forName(oracleDb_Driver);

36

37}catch(Exceptione){

38thrownewExceptionInInitializerError(e);

39}

40}

41

42/

43@Method:getOracleConnection

44@Description:获取Oracle数据库连接对象

45@Anthor:孤傲苍狼

46

47@returnConnection数据库连接对象

48@throwsSQLException

49/

50publicstaticConnectiongetOracleConnection()throwsSQLException{

51returnDriverManager.getConnection(oracleDb_Url,oracleDb_UserName,oracleDb_Password);

52}

53

54/

55@Method:release

56@Description:释放资源,

57要释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象

58@Anthor:孤傲苍狼

59

60@paramconn

61@paramst

62@paramrs

63/

64publicstaticvoidrelease(Connectionconn,Statementst,ResultSetrs){

65if(rs!=null){

66try{

67//关闭存储查询结果的ResultSet对象

68rs.close();

69}catch(Exceptione){

70e.printStackTrace();

71}

72rs=null;

73}

74if(st!=null){

75try{

76//关闭负责执行SQL命令的Statement对象

77st.close();

78}catch(Exceptione){

79e.printStackTrace();

80}

81}

82

83if(conn!=null){

84try{

85//关闭Connection数据库连接对象

86conn.close();

87}catch(Exceptione){

88e.printStackTrace();

89}

90}

91}

92}

复制代码

三、JDBC处理Oracle大数据



3.1、JDBC处理CLOB数据



复制代码

1packageme.gacl.demo;

2

3importjava.io.BufferedReader;

4importjava.io.BufferedWriter;

5importjava.io.FileReader;

6importjava.io.FileWriter;

7importjava.sql.Connection;

8importjava.sql.PreparedStatement;

9importjava.sql.ResultSet;

10importorg.junit.Test;

11importme.gacl.utils.JdbcUtils;

12

13/

14@ClassName:JdbcOperaOracleClob

15@Description:Oracle中字符型大型对象(CharacterLargeObject)数据处理

16@author:孤傲苍狼

17@date:2014-10-7下午3:53:19

18

19/

20publicclassJdbcOperaOracleClob{

21

22/

23CREATETABLETEST_CLOB(IDNUMBER(3),CLOBCOLCLOB)

24/

25/

26@Method:clobInsert

27@Description:往数据库中插入一个新的CLOB对象

28@Anthor:孤傲苍狼

29

30@throwsException

31/

32@Test

33publicvoidclobInsert()throwsException{

34Connectionconn=null;

35PreparedStatementstmt=null;

36ResultSetrs=null;

37conn=JdbcUtils.getOracleConnection();

38booleandefaultCommit=conn.getAutoCommit();

39/开启事务,设定不自动提交/

40conn.setAutoCommit(false);

41try{

42/插入一个空的CLOB对象/

43Stringsql="INSERTINTOTEST_CLOBVALUES(?,EMPTY_CLOB())";

44stmt=conn.prepareStatement(sql);

45stmt.setInt(1,1);

46stmt.executeUpdate();

47/查询此CLOB对象并锁定/

48sql="SELECTCLOBCOLFROMTEST_CLOBWHEREID=?FORUPDATE";

49stmt=conn.prepareStatement(sql);

50stmt.setInt(1,1);

51rs=stmt.executeQuery();

52if(rs.next()){

53/取出此CLOB对象/

54oracle.sql.CLOBclob=(oracle.sql.CLOB)rs.getClob("CLOBCOL");

55/向CLOB对象中写入数据/

56BufferedWriterout=newBufferedWriter(clob.getCharacterOutputStream());

57//这种方式获取的路径,其中的空格会被使用“%20”代替

58Stringpath=JdbcOperaClob.class.getClassLoader().getResource("data.txt").getPath();

59//将“%20”替换回空格

60path=path.replaceAll("%20","");

61BufferedReaderin=newBufferedReader(newFileReader(path));

62intc;

63while((c=in.read())!=-1){

64out.write(c);

65}

66in.close();

67out.close();

68}

69/正式提交/

70conn.commit();

71System.out.println("插入成功");

72}catch(Exceptionex){

73/出错回滚/

74conn.rollback();

75throwex;

76}finally{

77/恢复原提交状态/

78conn.setAutoCommit(defaultCommit);

79JdbcUtils.release(conn,stmt,rs);

80}

81

82}

83

84/

85@Method:clobRead

86@Description:CLOB对象读取

87@Anthor:孤傲苍狼

88

89@throwsException

90/

91@Test

92publicvoidclobRead()throwsException{

93Connectionconn=null;

94PreparedStatementstmt=null;

95ResultSetrs=null;

96conn=JdbcUtils.getOracleConnection();

97booleandefaultCommit=conn.getAutoCommit();

98conn.setAutoCommit(false);

99try{

100/查询CLOB对象/

101Stringsql="SELECTFROMTEST_CLOBWHEREID=?";

102stmt=conn.prepareStatement(sql);

103stmt.setInt(1,1);

104rs=stmt.executeQuery();

105if(rs.next()){

106/获取CLOB对象/

107oracle.sql.CLOBclob=(oracle.sql.CLOB)rs.getClob("CLOBCOL");

108/以字符形式输出/

109BufferedReaderin=newBufferedReader(clob.getCharacterStream());

110BufferedWriterout=newBufferedWriter(newFileWriter("D:\\2.txt"));

111intc;

112while((c=in.read())!=-1){

113out.write(c);

114}

115out.close();

116in.close();

117}

118}catch(Exceptionex){

119conn.rollback();

120throwex;

121}finally{

122/恢复原提交状态/

123conn.setAutoCommit(defaultCommit);

124JdbcUtils.release(conn,stmt,rs);

125}

126}

127

128/

129@Method:clobModify

130@Description:修改CLOB对象(是在原CLOB对象基础上进行覆盖式的修改)

131@Anthor:孤傲苍狼

132

133@throwsException

134/

135@Test

136publicvoidclobModify()throwsException{

137Connectionconn=null;

138PreparedStatementstmt=null;

139ResultSetrs=null;

140conn=JdbcUtils.getOracleConnection();

141booleandefaultCommit=conn.getAutoCommit();

142//开启事务

143conn.setAutoCommit(false);

144try{

145/查询CLOB对象并锁定/

146Stringsql="SELECTCLOBCOLFROMTEST_CLOBWHEREID=?FORUPDATE";

147stmt=conn.prepareStatement(sql);

148stmt.setInt(1,1);

149rs=stmt.executeQuery();

150if(rs.next()){

151/获取此CLOB对象/

152oracle.sql.CLOBclob=(oracle.sql.CLOB)rs.getClob("CLOBCOL");

153/进行覆盖式修改/

154BufferedWriterout=newBufferedWriter(clob.getCharacterOutputStream());

155//这种方式获取的路径,其中的空格会被使用“%20”代替

156Stringpath=JdbcOperaClob.class.getClassLoader().getResource("data2.txt").getPath();

157//将“%20”替换回空格

158path=path.replaceAll("%20","");

159BufferedReaderin=newBufferedReader(newFileReader(path));

160intc;

161while((c=in.read())!=-1){

162out.write(c);

163}

164in.close();

165out.close();

166}

167/提交事务/

168conn.commit();

169}catch(Exceptionex){

170/出错回滚事务/

171conn.rollback();

172throwex;

173}finally{

174/恢复原提交状态/

175conn.setAutoCommit(defaultCommit);

176JdbcUtils.release(conn,stmt,rs);

177}

178}

179

180/

181@Method:clobReplace

182@Description:替换CLOB对象(将原CLOB对象清除,换成一个全新的CLOB对象)

183@Anthor:孤傲苍狼

184

185@throwsException

186/

187@Test

188publicvoidclobReplace()throwsException{

189Connectionconn=null;

190PreparedStatementstmt=null;

191Resuwww.wang027.comltSetrs=null;

192conn=JdbcUtils.getOracleConnection();

193booleandefaultCommit=conn.getAutoCommit();

194//开启事务

195conn.setAutoCommit(false);

196try{

197/清空原CLOB对象/

198Stringsql="UPDATETEST_CLOBSETCLOBCOL=EMPTY_CLOB()WHEREID=?";

199stmt=conn.prepareStatement(sql);

200stmt.setInt(1,1);

201stmt.executeUpdate();

202

203/查询CLOB对象并锁定/

204sql="SELECTCLOBCOLFROMTEST_CLOBWHEREID=?FORUPDATE";

205stmt=conn.prepareStatement(sql);

206stmt.setInt(1,1);

207rs=stmt.executeQuery();

208if(rs.next()){

209/获取此CLOB对象/

210oracle.sql.CLOBclob=(oracle.sql.CLOB)rs.getClob("CLOBCOL");

211/更新数据/

212BufferedWriterout=newBufferedWriter(clob.getCharacterOutputStream());

213//这种方式获取的路径,其中的空格会被使用“%20”代替

214Stringpath=JdbcOperaClob.class.getClassLoader().getResource("db.properties").getPath();

215//将“%20”替换回空格

216path=path.replaceAll("%20","");

217BufferedReaderin=newBufferedReader(newFileReader(path));

218intc;

219while((c=in.read())!=-1){

220out.write(c);

221}

222in.close();

223out.close();

224}

225/正式提交/

226conn.commit();

227}catch(Exceptionex){

228/出错回滚/

229conn.rollback();

230throwex;

231}finally{

232/恢复原提交状态/

233conn.setAutoCommit(defaultCommit);

234JdbcUtils.release(conn,stmt,rs);

235}

236}

237}

复制代码

3.2、JDBC处理BLOB数据



Oracle定义了一个BLOB字段用于保存二进制数据,但这个字段并不能存放真正的二进制数据,只能向这个字段存一个指针,然后把数据放到指针所指向的Oracle的LOB段中,LOB段是在数据库内部表的一部分。因而在操作Oracle的Blob之前,必须获得指针(定位器)才能进行Blob数据的读取和写入。

如何获得表中的Blob指针呢?可以先使用insert语句向表中插入一个空的blob(调用oracle的函数empty_blob()),这将创建一个blob的指针,然后再把这个empty的blob的指针查询出来,这样就可得到BLOB对象,从而读写blob数据了。



1、插入空blob:insertintotestblob(id,image)values(?,empty_blob())

2、获得blob的cursor:



selectimagefromtestblobwhereid=?forupdate注意:必须加forupdate锁定该行,直至该行被修改完毕,保证不产生并发冲突。



Blobb=rs.getBlob("image");



3、利用io和获取到的cursor往数据库读写数据

注意:以上操作需开启事务。



BLOB对象的存取范例



复制代码

1packageme.gacl.demo;

2

3importjava.io.BufferedInputStream;

4importjava.io.BufferedOutputStream;

5importjava.io.FileOutputStream;

6importjava.sql.Connection;

7importjava.sql.PreparedStatement;

8importjava.sql.ResultSet;

9importorg.junit.Test;

10importme.gacl.utils.JdbcUtils;

11

12/

13@ClassName:JdbcOperaOracleBlob

14@Description:Oracle中大数据处理

15@author:孤傲苍狼

16@date:2014-10-7下午3:53:19

17

18/

19publicclassJdbcOperaOracleBlob{

20

21/

22@Method:blobInsert

23@Description:向数据库中插入一个新的BLOB对象

24@Anthor:孤傲苍狼

25

26@throwsException

27/

28@Test

29publicvoidblobInsert()throwsException{

30Connectionconn=null;

31PreparedStatementstmt=null;

32ResultSetrs=null;

33booleandefaultCommit=true;

34try{

35conn=JdbcUtils.getOracleConnection();

36//得到数据库事务处理的默认提交方式

37defaultCommit=conn.getAutoCommit();

38//1、开启事务

39conn.setAutoCommit(false);

40//2、插入一个空的BLOB对象

41Stringsql="INSERTINTOTEST_BLOBVALUES(?,EMPTY_BLOB())";

42stmt=conn.prepareStatement(sql);

43stmt.setInt(1,1);

44stmt.executeUpdate();

45//3、查询此BLOB对象并锁定。注意:必须加forupdate锁定该行,直至该行被修改完毕,保证不产生并发冲突

46sql="SELECTBLOBCOLFROMTEST_BLOBWHEREID=?FORUPDATE";

47stmt=conn.prepareStatement(sql);

48stmt.setInt(1,1);

49rs=stmt.executeQuery();

50if(rs.next()){

51//4、取出此BLOB对象,并强制转换成Oracle的BLOB对象

52oracle.sql.BLOBblob=(oracle.sql.BLOB)rs.getBlob("BLOBCOL");

53//5、使用IO向BLOB对象中写入数据

54BufferedOutputStreamout=newBufferedOutputStream(blob.getBinaryOutputStream());

55BufferedInputStreamin=newBufferedInputStream(JdbcOperaOracleBlob.class.getClassLoader().getResourceAsStream("01.jpg"));

56intc;

57while((c=in.read())!=-1){

58out.write(c);

59}

60in.close();

61out.close();

62}

63//6、提交事务

64conn.commit();

65}catch(Exceptionex){

66//7、出错回滚事务

67conn.rollback();

68throwex;

69}finally{

70//8、恢复数据库事务处理的默认提交方式

71conn.setAutoCommit(defaultCommit);

72//释放资源

73JdbcUtils.release(conn,stmt,rs);

74}

75

76}

77

78/

79@Method:blobModify

80@Description:修改BLOB对象(是在原BLOB对象基础上进行覆盖式的修改)

81@Anthor:孤傲苍狼

82

83@throwsException

84/

85@Test

86publicvoidblobModify()throwsException{

87Connectionconn=null;

88PreparedStatementstmt=null;

89ResultSetrs=null;

90booleandefaultCommit=true;

91try{

92conn=JdbcUtils.getOracleConnection();

93//得到数据库事务处理的默认提交方式

94defaultCommit=conn.getAutoCommit();

95//1、开启事务

96conn.setAutoCommit(false);

97//2、查询此BLOB对象并锁定。注意:必须加forupdate锁定该行,直至该行被修改完毕,保证不产生并发冲突

98Stringsql="SELECTBLOBCOLFROMTEST_BLOBWHEREID=?FORUPDATE";

99stmt=conn.prepareStatement(sql);

100stmt.setInt(1,1);

101rs=stmt.executeQuery();

102if(rs.next()){

103//3、取出此BLOB对象,并强制转换成Oracle的BLOB对象

104oracle.sql.BLOBblob=(oracle.sql.BLOB)rs.getBlob("BLOBCOL");

105//4、使用IO向BLOB对象中写入数据

106BufferedOutputStreamout=newBufferedOutputStream(blob.getBinaryOutputStream());

107BufferedInputStreamin=newBufferedInputStream(JdbcOperaOracleBlob.class.getClassLoader().getResourceAsStream("02.jpg"));

108intc;

109while((c=in.read())!=-1){

110out.write(c);

111}

112in.close();

113out.close();

114}

115//5、提交事务

116conn.commit();

117}catch(Exceptionex){

118//6、出错回滚事务

119conn.rollback();

120throwex;

121}finally{

122//8、恢复数据库事务处理的默认提交方式

123conn.setAutoCommit(defaultCommit);

124//释放资源

125JdbcUtils.release(conn,stmt,rs);

126}

127}

128

129/

130@Method:blobReplace

131@Description:替换BLOB对象(将原BLOB对象清除,换成一个全新的BLOB对象)

132@Anthor:孤傲苍狼

133

134@throwsException

135/

136@Test

137publicvoidblobReplace()throwsException{

138Connectionconn=null;

139PreparedStatementstmt=null;

140ResultSetrs=null;

141booleandefaultCommit=true;

142try{

143conn=JdbcUtils.getOracleConnection();

144//得到数据库事务处理的默认提交方式

145defaultCommit=conn.getAutoCommit();

146//1、开启事务

147conn.setAutoCommit(false);

148//2、清空原BLOB对象

149Stringsql="UPDATETEST_BLOBSETBLOBCOL=EMPTY_BLOB()WHEREID=?";

150stmt=conn.prepareStatement(sql);

151stmt.setInt(1,1);

152stmt.executeUpdate();

153//3、查询此BLOB对象并锁定。注意:必须加forupdate锁定该行,直至该行被修改完毕,保证不产生并发冲突

154sql="SELECTBLOBCOLFROMTEST_BLOBWHEREID=?FORUPDATE";

155stmt=conn.prepareStatement(sql);

156stmt.setInt(1,1);

157rs=stmt.executeQuery();

158if(rs.next()){

159//4、取出此BLOB对象,并强制转换成Oracle的BLOB对象

160oracle.sql.BLOBblob=(oracle.sql.BLOB)rs.getBlob("BLOBCOL");

161//5、使用IO向BLOB对象中写入数据

162BufferedOutputStreamout=newBufferedOutputStream(blob.getBinaryOutputStream());

163BufferedInputStreamin=newBufferedInputStream(JdbcOperaOracleBlob.class.getClassLoader().getResourceAsStream("01.jpg"));

164intc;

165while((c=in.read())!=-1){

166out.write(c);

167}

168in.close();

169out.close();

170}

171//6、提交事务

172conn.commit();

173}catch(Exceptionex){

174//7、出错回滚事务

175conn.rollback();

176throwex;

177}finally{

178//8、恢复数据库事务处理的默认提交方式

179conn.setAutoCommit(defaultCommit);

180//释放资源

181JdbcUtils.release(conn,stmt,rs);

182}

183}

184

185/

186@Method:blobRead

187@Description:BLOB对象读取

188@Anthor:孤傲苍狼

189

190@throwsException

191/

192@Test

193publicvoidblobRead()throwsException{

194Connectionconn=null;

195PreparedStatementstmt=null;

196ResultSetrs=null;

197booleandefaultCommit=true;

198try{

199conn=JdbcUtils.getOracleConnection();

200//得到数据库事务处理的默认提交方式

201defaultCommit=conn.getAutoCommit();

202//1、开启事务

203conn.setAutoCommit(false);

204//2、查询BLOB对象

205Stringsql="SELECTBLOBCOLFROMTEST_BLOBWHEREID=?";

206stmt=conn.prepareStatement(sql);

207stmt.setInt(1,1);

208rs=stmt.executeQuery();

209if(rs.next()){

210//3、取出此BLOB对象,并强制转换成Oracle的BLOB对象

211oracle.sql.BLOBblob=(oracle.sql.BLOB)rs.getBlob("BLOBCOL");

212//4、以二进制流的形式输出

213BufferedOutputStreamout=newBufferedOutputStream(newFileOutputStream("D:/1.jpg"));

214BufferedInputStreamin=newBufferedInputStream(blob.getBinaryStream());

215intc;

216while((c=in.read())!=-1){

217out.write(c);

218}

219in.close();

220out.close();

221}

222//5、提交事务

223conn.commit();

224}catch(Exceptionex){

225//6、出错回滚事务

226conn.rollback();

227throwex;

228}finally{

229//8、恢复数据库事务处理的默认提交方式

230conn.setAutoCommit(defaultCommit);

231//释放资源

232JdbcUtils.release(conn,stmt,rs);

233}

234

235}

236}

复制代码

四、使用JDBC处理Oracle大数据总结



通过JDBC操纵Oracle数据库的LOB字段,不外乎插入、修改、替换、读取四种方式,掌握起来并不难。观察上述程序对LOB类型字段的存取,我们可以看出,较之其它类型字段,有下面几个显著不同的特点:



1、必须取消自动提交。



存取操作开始前,必须用setAutoCommit(false)取消自动提交。其它类型字段则无此特殊要求。这是因为存取LOB类型字段时,通常要进行多次操作可以完成。不这样的话,Oracle将抛出“读取违反顺序”的错误。



2、插入方式不同。



LOB数据不能象其它类型数据一样直接插入(INSERT)。插入前必须先插入一个空的LOB对象,CLOB类型的空对象为EMPTY_CLOB(),BLOB类型的空对象为EMPTY_BLOB()。之后通过SELECT命令查询得到先前插入的记录并锁定,继而将空对象修改为所要插入的LOB对象。



3、修改方式不同。



其它类型的字段修改时,用UPDATE…SET…命令即可。而LOB类型字段,则只能用SELECT…FORUPDATE命令将记录查询出来并锁定,然后才能修改。且修改也有两种改法:一是在原数据基础上的修改(即覆盖式修改),执行SELECT…FORUPDATE后再改数据;二是替换(先将原数据清掉,再修改),先执行UPDATE命令将LOB字段之值设为空的LOB对象,然后进行第一种改法。建议使用替换的方法,以实现与其它字段UPDATE操作后一样的效果。



4、存取时应使用由数据库JDBC驱动程序提供的LOB操作类。



对于Oracle数据库,应使用oracle.sql.CLOB和oracle.sql.BLOB。不使用由数据库JDBC驱动程序提供的LOB类时,程序运行时易于出现“抽象方法调用”的错误,这是因为JDBC所定义的java.sql.Clob与java.sql.Blob接口,其中的一些方法并未在数据库厂家提供的驱动程序中真正实现。



5、存取手段与文件操作相仿。



对于BLOB类型,应用InputStream/OutputStream类,此类不进行编码转换,逐个字节存取。oracle.sql.BLOB类相应提供了getBinaryStream()和getBinaryOutputStream()两个方法,前一个方法用于读取Oracle的BLOB字段,后一个方法用于将数据写入Oracle的BLOB字段。



对于CLOB类型,应用Reader/Writer类,此类进行编码转换。oracle.sql.CLOB类相应提供了getCharacterStream()和getCharacterOutputStream()两个方法,前一个方法用于读取Oracle的CLOB字段,后一个方法用于将数据写入Oracle的CLOB字段。



需要说明的是,为了大幅提高程序执行效率,对BLOB/CLOB字段的读写操作,应该使用缓冲操作类(带Buffered前缀),即:BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。例程中全部使用了缓冲操作类。

献花(0)
+1
(本文系thedust79首藏)