your programing

자바 : PreparedStatement를 사용하여 MySQL에 여러 행 삽입

lovepro 2020. 10. 4. 12:53
반응형

자바 : PreparedStatement를 사용하여 MySQL에 여러 행 삽입


Java를 사용하여 한 번에 여러 행을 MySQL 테이블에 삽입하고 싶습니다. 행 수는 동적입니다. 과거에는 ...

for (String element : array) {
    myStatement.setString(1, element[0]);
    myStatement.setString(2, element[1]);

    myStatement.executeUpdate();
}

MySQL 지원 구문을 사용하도록 최적화하고 싶습니다.

INSERT INTO table (col1, col2) VALUES ('val1', 'val2'), ('val1', 'val2')[, ...]

그러나를 사용하면 PreparedStatement얼마나 많은 요소 array가 포함 될지 미리 알지 못하기 때문에 이것을 수행하는 방법을 모릅니다 . 으로 가능하지 않다면 PreparedStatement어떻게 할 수 있습니까 (그리고 여전히 배열의 값을 이스케이프 처리)?


를 사용하여 배치를 PreparedStatement#addBatch()만들고 실행할 수 있습니다 PreparedStatement#executeBatch().

다음은 시작 예입니다.

public void save(List<Entity> entities) throws SQLException {
    try (
        Connection connection = database.getConnection();
        PreparedStatement statement = connection.prepareStatement(SQL_INSERT);
    ) {
        int i = 0;

        for (Entity entity : entities) {
            statement.setString(1, entity.getSomeProperty());
            // ...

            statement.addBatch();
            i++;

            if (i % 1000 == 0 || i == entities.size()) {
                statement.executeBatch(); // Execute every 1000 items.
            }
        }
    }
}

일부 JDBC 드라이버 및 / 또는 DB에는 배치 길이에 제한이있을 수 있으므로 1000 개 항목마다 실행됩니다.

참조 :


MySQL 드라이버를 사용하는 경우 연결 매개 변수 rewriteBatchedStatements를 true 로 설정 해야합니다 ( jdbc:mysql://localhost:3306/TestDB?**rewriteBatchedStatements=true**).

이 매개 변수를 사용하면 테이블이 한 번만 잠기고 인덱스가 한 번만 업데이트 될 때 명령문이 대량 삽입으로 다시 작성됩니다. 그래서 훨씬 빠릅니다.

이 매개 변수가 없으면 유일한 장점은 더 깨끗한 소스 코드입니다.


SQL 문을 동적으로 만들 수있는 경우 다음 해결 방법을 수행 할 수 있습니다.

    String myArray[][] = { { "1-1", "1-2" }, { "2-1", "2-2" },
            { "3-1", "3-2" } };

    StringBuffer mySql = new StringBuffer(
            "insert into MyTable (col1, col2) values (?, ?)");

    for (int i = 0; i < myArray.length - 1; i++) {
        mySql.append(", (?, ?)");
    }

    myStatement = myConnection.prepareStatement(mySql.toString());

    for (int i = 0; i < myArray.length; i++) {
        myStatement.setString(i, myArray[i][1]);
        myStatement.setString(i, myArray[i][2]);
    }
    myStatement.executeUpdate();

테이블에 자동 증분이 있고 액세스해야하는 경우 다음 방법을 사용할 수 있습니다. 사용 된 드라이버에 따라 다르므로 Statement에서 getGeneratedKeys ()를 사용하기 전에 먼저 테스트하십시오. 아래 코드는 Maria DB 10.0.12 및 Maria JDBC 드라이버 1.2에서 테스트되었습니다.

배치 크기를 늘리면 성능이 어느 정도만 향상된다는 점을 기억하십시오. 설정에서 배치 크기를 500 이상으로 늘리면 실제로 성능이 저하됩니다.

public Connection getConnection(boolean autoCommit) throws SQLException {
    Connection conn = dataSource.getConnection();
    conn.setAutoCommit(autoCommit);
    return conn;
}

private void testBatchInsert(int count, int maxBatchSize) {
    String querySql = "insert into batch_test(keyword) values(?)";
    try {
        Connection connection = getConnection(false);
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        boolean success = true;
        int[] executeResult = null;
        try {
            pstmt = connection.prepareStatement(querySql, Statement.RETURN_GENERATED_KEYS);
            for (int i = 0; i < count; i++) {
                pstmt.setString(1, UUID.randomUUID().toString());
                pstmt.addBatch();
                if ((i + 1) % maxBatchSize == 0 || (i + 1) == count) {
                    executeResult = pstmt.executeBatch();
                }
            }
            ResultSet ids = pstmt.getGeneratedKeys();
            for (int i = 0; i < executeResult.length; i++) {
                ids.next();
                if (executeResult[i] == 1) {
                    System.out.println("Execute Result: " + i + ", Update Count: " + executeResult[i] + ", id: "
                            + ids.getLong(1));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            success = false;
        } finally {
            if (rs != null) {
                rs.close();
            }
            if (pstmt != null) {
                pstmt.close();
            }
            if (connection != null) {
                if (success) {
                    connection.commit();
                } else {
                    connection.rollback();
                }
                connection.close();
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

@Ali Shakiba your code needs some modification. Error part:

for (int i = 0; i < myArray.length; i++) {
     myStatement.setString(i, myArray[i][1]);
     myStatement.setString(i, myArray[i][2]);
}

Updated code:

String myArray[][] = {
    {"1-1", "1-2"},
    {"2-1", "2-2"},
    {"3-1", "3-2"}
};

StringBuffer mySql = new StringBuffer("insert into MyTable (col1, col2) values (?, ?)");

for (int i = 0; i < myArray.length - 1; i++) {
    mySql.append(", (?, ?)");
}

mysql.append(";"); //also add the terminator at the end of sql statement
myStatement = myConnection.prepareStatement(mySql.toString());

for (int i = 0; i < myArray.length; i++) {
    myStatement.setString((2 * i) + 1, myArray[i][1]);
    myStatement.setString((2 * i) + 2, myArray[i][2]);
}

myStatement.executeUpdate();

we can be submit multiple updates together in JDBC to submit batch updates.

we can use Statement, PreparedStatement, and CallableStatement objects for bacth update with disable autocommit

addBatch() and executeBatch() functions are available with all statement objects to have BatchUpdate

here addBatch() method adds a set of statements or parameters to the current batch.

참고URL : https://stackoverflow.com/questions/4355046/java-insert-multiple-rows-into-mysql-with-preparedstatement

반응형