java从oracle中读取大量数据写出到文件

以你之姓@ 2022-12-07 04:28 540阅读 0赞

java从oracle中读取大量数据写出到文件

背景:项目中需要从oracle中读取表字段并以指定间隔符拼接字段,输出到txt。每张表的数据量大概在2000W左右,因为是只需要读一张表指定字段的全部数据,也不需要考虑查询优化,只针对表读取规模进行优化即可。

版本oracle 11G

思路一:

使用oracle语句对数据表进行分页读取,这里应注意到的是rowid效率和rownum效率问题,还有使不使用order by

  1. SELECT t.*
  2. FROM a t, (SELECT ROWNUM rn, c.*
  3. FROM (SELECT ROWID k
  4. FROM a
  5. ORDER BY ID) c) b
  6. WHERE t.ROWID = b.k AND b.rn BETWEEN 10001 AND 20000;

有一篇对比文章,大家可以看一下 http://www.itpub.net/thread-1603830-1-1.html

这个思路对我的需求来说也不太适合,分页读取确实缩短了查询时间,但是对于上千万的大表来说,越往后分页花的时间越长,整体来说效率提升不多大。

思路二:

在写数据时,使用多线程,提升写的效率,测试证明,我的效率瓶颈是在读取数据方面,不是写数据方面。

思路三:

使用ResultSet对结果集进行分批读取,开始的时候没想到ResultSet直接支持了分批读取,在前面两个思路上花费了不少时间。

先讲解下再贴代码
ResultSet的常见用法:点击跳转查看

大多数文章知识讲解了常见方法及参数的设定,ResultSet的setFetchSize()setMaxRows() 缺很少有人提及

  1. 简单来说
  2. setFetchSize() :是设置ResultSet每次向数据库取的行数
  3. 例如:rs.setFetchSize(100),ResultSet每次向数据库读取100条数据,
  4. 之后下一百条数据的读取是在ResultSet内部完成的,不需要手动去进行调用或定位数据从哪行开始。
  5. setMaxRows() :是设置Resultset最多返回的行数,不需要读取全部数据,只要特定行数的数据,可以选择此方法。

有篇文章里分析的还算可以:
JDBC读取数据优化setFetchSize
JDBC读取数据优化-fetch size

另外如果设置的

  1. stmt = destCon.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);

可能会报这个错
在这里插入图片描述

  1. 这时需要把
  2. ResultSet.TYPE_SCROLL_SENSITIVE
  3. 改为
  4. ResultSet.TYPE_SCROLL_INSENSITIVE,

下面贴上我的代码

  1. public static void main(String[] args) throws SQLException, ClassNotFoundException, IOException {
  2. String selsql;
  3. Connection destCon = null;
  4. Statement stmt = null;
  5. BufferedWriter output = null;
  6. long rowCount = 0L;
  7. int colCounts = 0;
  8. ResultSet res = null;
  9. long flen = 0L;
  10. selsql = "select RANDOM_STRING from myTestTable";
  11. destCon = getConnection();
  12. int fileCount = 1;
  13. EtlRuler etlRuler = new EtlRuler();
  14. etlRuler.setLocal_path("E:\\web_project\\");
  15. etlRuler.setFile_name("test010.txt");
  16. String filePath = etlRuler.getLocal_path() + etlRuler.getFile_name().replace("${NUM}", "00" + fileCount);
  17. etlRuler.getDataPath().add(filePath);
  18. File file = new File(etlRuler.getDataPath().get(fileCount - 1));
  19. if (!file.exists()) {
  20. file.createNewFile();
  21. }
  22. StringBuilder line = new StringBuilder();
  23. output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false), StandardCharsets.UTF_8));
  24. stmt = destCon.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
  25. res = stmt.executeQuery(selsql);
  26. res.setFetchSize(2000);
  27. if (res == null || !res.next()) {
  28. System.out.println("数据文件sql无数据!");
  29. // throw new Exception("数据文件sql无数据!");
  30. }
  31. assert res != null;
  32. res.previous();
  33. // 获取字段元信息
  34. ResultSetMetaData rsmd1 = res.getMetaData();
  35. colCounts = rsmd1.getColumnCount();
  36. int j = 0;
  37. String str = "";
  38. while (res.next()) {
  39. //System.out.println("开始读取数据" + rowCount++);
  40. // 打印进度
  41. rowCount++;
  42. if (rowCount % 2000 == 0) {
  43. Date date = new Date();
  44. //20w条数据的时候写入一下,之后清空StringBuilder,重新添加数据
  45. System.out.println("执行时间:" + date);
  46. System.out.println(rowCount + " ----rows proceed");
  47. // output.write(line.toString());
  48. // output.flush();
  49. // line.delete(0, line.length());
  50. }
  51. for (int i = 1; i <= colCounts; i++) {
  52. //line.append(res.getString(i)).append("\n");
  53. str = res.getString(i)+"\n";
  54. }
  55. output.write(str);
  56. output.flush();
  57. str = "";
  58. //System.out.println("开始写入数据");
  59. if (file.length() > (1024 * 500)) {
  60. if (etlRuler.getFile_name().contains("${NUM}")) {
  61. //output.write(line.toString());
  62. //output.flush();
  63. //line.delete(0,line.length());
  64. fileCount++;
  65. System.out.println("创建新文件");
  66. String newfilePath = etlRuler.getLocal_path() + etlRuler.getFile_name().replace("${NUM}", "00" + fileCount);
  67. etlRuler.getDataPath().add(newfilePath);
  68. file = new File(etlRuler.getDataPath().get(fileCount - 1));
  69. if (!file.exists()) {
  70. file.createNewFile();
  71. }
  72. output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false),
  73. StandardCharsets.UTF_8));
  74. }
  75. }
  76. }
  77. //System.out.println("开始写入数据");
  78. output.write(line.toString());
  79. output.flush();
  80. output.close();
  81. flen = file.length();
  82. System.out.println("文件大小:" + flen);
  83. }
  84. public static Connection getConnection() throws ClassNotFoundException, SQLException {
  85. Class.forName("oracle.jdbc.driver.OracleDriver");
  86. Connection con = null;
  87. con = DriverManager.getConnection(
  88. "jdbc:oracle:thin:@" + ip + ":" + port + ":" + sid, user,
  89. password); //设置数据库连接字符串
  90. return con;
  91. }

发表评论

表情:
评论列表 (有 0 条评论,540人围观)

还没有评论,来说两句吧...

相关阅读