使用 JDBC 预定义的语句批量插入

可以使用预定义的 INSERT 语句(仅需设置一次即可重复调用的服务器端语句)将数据批量加载到 Vertica 中。您可以使用包含表示数据的问号占位符的 SQL 语句将 PreparedStatement 类的成员实例化。例如:

PreparedStatement pstmt = conn.prepareStatement(
                    "INSERT INTO customers(last, first, id) VALUES(?,?,?)");

然后,可以对 PreparedStatement 对象使用特定于数据类型的方法(例如 setString()setInt())来设置参数。设置参数后,调用 addBatch() 方法以将行添加到批中。整个数据批准备就绪后,调用 executeBatch() 方法以执行批量插入。

在后台,批量插入会转换为 COPY 语句。如果已禁用连接的 AutoCommit 参数,则 Vertica 会保持打开 COPY 语句并使用该语句加载后续的批,直至事务已提交或者游标已关闭或应用程序执行任何其他操作(或者使用其他 StatementPreparedStatement 对象执行任何语句)为止。使用单个 COPY 语句进行多个批量插入可以更高效地加载数据。如果要加载多个批,应禁用数据库的 AutoCommit 属性以提高效率。

执行批量插入时,可以试验各个批大小和行大小以确定可提供最佳性能的设置。

以下示例演示了使用预定义的语句批量插入数据。

import java.sql.*;
import java.util.Properties;

public class BatchInsertExample {
    public static void main(String[] args) {
        Properties myProp = new Properties();
        myProp.put("user", "ExampleUser");
        myProp.put("password", "password123");

     //Set streamingBatchInsert to True to enable streaming mode for batch inserts.
     //myProp.put("streamingBatchInsert", "True");

     Connection conn;
        try {
            conn = DriverManager.getConnection(
                            "jdbc:vertica://VerticaHost:5433/ExampleDB",
                            myProp);
            // establish connection and make a table for the data.
            Statement stmt = conn.createStatement();


            // Set AutoCommit to false to allow Vertica to reuse the same
            // COPY statement
            conn.setAutoCommit(false);


            // Drop table and recreate.
            stmt.execute("DROP TABLE IF EXISTS customers CASCADE");
            stmt.execute("CREATE TABLE customers (CustID int, Last_Name"
                            + " char(50), First_Name char(50),Email char(50), "
                            + "Phone_Number char(12))");
            // Some dummy data to insert.
            String[] firstNames = new String[] { "Anna", "Bill", "Cindy",
                            "Don", "Eric" };
            String[] lastNames = new String[] { "Allen", "Brown", "Chu",
                            "Dodd", "Estavez" };
            String[] emails = new String[] { "aang@example.com",
                            "b.brown@example.com", "cindy@example.com",
                            "d.d@example.com", "e.estavez@example.com" };
            String[] phoneNumbers = new String[] { "123-456-7890",
                            "555-444-3333", "555-867-5309",
                            "555-555-1212", "781-555-0000" };
            // Create the prepared statement
            PreparedStatement pstmt = conn.prepareStatement(
                            "INSERT INTO customers (CustID, Last_Name, " +
                            "First_Name, Email, Phone_Number)" +
                            " VALUES(?,?,?,?,?)");
            // Add rows to a batch in a loop. Each iteration adds a
            // new row.
            for (int i = 0; i < firstNames.length; i++) {
                // Add each parameter to the row.
                pstmt.setInt(1, i + 1);
                pstmt.setString(2, lastNames[i]);
                pstmt.setString(3, firstNames[i]);
                pstmt.setString(4, emails[i]);
                pstmt.setString(5, phoneNumbers[i]);
                // Add row to the batch.
                pstmt.addBatch();
            }

            try {
                // Batch is ready, execute it to insert the data
                pstmt.executeBatch();
            } catch (SQLException e) {
                System.out.println("Error message: " + e.getMessage());
                return; // Exit if there was an error
            }

            // Commit the transaction to close the COPY command
            conn.commit();


            // Print the resulting table.
            ResultSet rs = null;
            rs = stmt.executeQuery("SELECT CustID, First_Name, "
                            + "Last_Name FROM customers ORDER BY CustID");
            while (rs.next()) {
                System.out.println(rs.getInt(1) + " - "
                                + rs.getString(2).trim() + " "
                                + rs.getString(3).trim());
            }
            // Cleanup
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

运行此示例代码后的结果如下所示:

1 - Anna Allen
2 - Bill Brown
3 - Cindy Chu
4 - Don Dodd
5 - Eric Estavez

流式批量插入

默认情况下,Vertica 通过缓存每个行并在用户调用 executeBatch() 方法时插入缓存来执行批量插入。Vertica 也支持流式批量插入。流式批量插入在用户每次调用 addBatch() 时将行添加到数据库中。流式批量插入可提高数据库性能,因为它能够进行并行处理并降低内存需求。

若要启用流式批量插入,请将 streamingBatchInsert 属性设置为 True。以上代码示例包含一个行,该行启用了 streamingBatchInsert 模式。移除 // 注释标记可启用该行并激活流式批量插入。

下表介绍了各种批量插入方法及其默认批量插入模式和流式批量插入模式之间的行为差异。

注意

  • 使用 PreparedStatement.setFloat() 方法会导致出现舍入误差。如果精度很重要,请改为使用 .setDouble() 方法。

  • 预定义语句时,PreparedStatement 对象会缓存连接的 AutoCommit 属性。以后对 AutoCommit 属性进行的更改不会影响预定义的语句。