普通读取是指通过JDBC的Statement
或PreparedStatement
执行SQL查询,JDBC驱动会阻塞的一次性读取全部查询的数据到 JVM 内存中。这种方式适用于小型数据集的读取。
在普通读取中,当执行查询时,JDBC会将整个结果集从数据库加载到内存中。开发者可以通过ResultSet
对象逐行访问数据。
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
String url = "jdbc:mysql://localhost:3307/test?useSSL=false";
connection = DriverManager.getConnection(url, user, password);
statement = connection.createStatement();
resultSet = statement.executeQuery("SELECT * FROM table_name");
while (resultSet.next()) {
System.out.println(resultSet.getString("column_name"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// close
if (resultSet != null) resultSet.close();
if (statement != null) statement.close();
if (connection != null) connection.close();
}
OutOfMemoryError
。游标读取是指通过JDBC的Statement
或PreparedStatement
使用游标逐行读取数据。游标允许在结果集中移动,适合处理较大的数据集。
游标读取通过在数据库中维护一个指向结果集的指针,允许逐行访问数据。每次读取一行数据,游标向前移动,直到结果集结束。
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
String url ="jdbc:mysql://localhost:3307/test?useSSL=false&useCursorFetch=true";
connection = DriverManager.getConnection(url, user, password);
preparedStatement = connection.prepareStatement("SELECT * FROM table_name", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
preparedStatement.setFetchSize(100); //set fetchSize
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("column_name"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// close reources
if (resultSet != null) resultSet.close();
if (preparedStatement != null) preparedStatement.close();
if (connection != null) connection.close();
}
流式读取是指通过JDBC的Statement
或PreparedStatement
以流的方式读取数据,适合处理非常大的数据集。
流式读取通过设置ResultSet
的类型和并发模式,允许在不将整个结果集加载到内存的情况下,逐行读取数据。通常结合setFetchSize()
方法来控制每次从数据库中获取的行数。
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
String url = "jdbc:mysql://localhost:3307/test?useSSL=false";
connection = DriverManager.getConnection(url, user, password);
preparedStatement = connection.prepareStatement("SELECT * FROM table_name", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
preparedStatement.setFetchSize(1000); // 设置每次读取的行数
//OR USEING com.mysql.jdbc.StatementImpl
//((StatementImpl) statement).enableStreamingResults();
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("column_name"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (resultSet != null) resultSet.close();
if (preparedStatement != null) preparedStatement.close();
if (connection != null) connection.close();
}
fetch size
。WARN ] 2024-12-26 09:36:50.365 [] job-file-log-676bc326966a463e08520799 - [srtosr][sr35] - Query 'his_config_info_exp' snapshot row size failed: java.lang.RuntimeException: io.tapdata.flow.engine.V2.exception.node.NodeException: Query table 'his_config_info_exp' count failed: No operations allowed after connection closed.
java.util.concurrent.CompletionException: java.lang.RuntimeException: io.tapdata.flow.engine.V2.exception.node.NodeException: Query table 'his_config_info_exp' count failed: No operations allowed after connection closed.
at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1643)
at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1632)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
在选择MySQL的数据读取方式时,需要根据具体的应用场景和数据集大小来决定:
根据实际需求,选择合适的读取方式可以提高应用程序的性能和可扩展性。