다음을 통해 공유


JDBC 드라이버에서 대량 복사 사용

JDBC 드라이버 다운로드

Microsoft SQL Server에는 bcp라는 많이 사용되는 명령줄 유틸리티가 있어 SQL Server 데이터베이스의 테이블이나 뷰로 큰 파일을 신속하게 대량 복사할 수 있습니다. SQLServerBulkCopy 클래스를 사용하면 이와 유사한 기능을 제공하는 코드 솔루션을 Java로 작성할 수 있습니다. INSERT 문 같은 다른 방법으로도 SQL Server 테이블에 데이터를 로드할 수 있지만 SQLServerBulkCopy는 다른 방법에 비해 성능이 크게 뛰어납니다.

SQLServerBulkCopy 클래스는 SQL Server 테이블에만 데이터를 쓰는 데 사용할 수 있습니다. 그러나 데이터 원본은 SQL Server로 제한되지 않으며, ResultSet, RowSet, ISQLServerBulkRecord 구현으로 데이터를 읽을 수 있는 한 모든 데이터 원본을 사용할 수 있습니다.

참고 항목

ISQLServerBulkData을(를) 대량 복사 작업을 수행할 시 사용하는 것은 현재 완전히 지원되지 않으며, 이 데이터 소스 유형을 사용할 때 오류가 발생할 수 있습니다. 대신 ResultSet, RowSet, 또는 ISQLServerBulkRecord을(를) 사용하는 것이 좋습니다.

SQLServerBulkCopy 클래스를 사용하면 다음을 수행할 수 있습니다.

  • 단일 대량 복사 작업

  • 여러 대량 복사 작업

  • 트랜잭션 내에서의 대량 복사 작업

참고 항목

SQLServerBulkCopy 클래스를 지원하지 않는 Microsoft JDBC Driver 4.1 for SQL Server 이하 버전을 사용하는 경우 SQL Server Transact-SQL BULK INSERT 문을 대신 실행할 수 있습니다.

대량 복사 예제 설정

SQLServerBulkCopy 클래스는 SQL Server 테이블에만 데이터를 쓰는 데 사용할 수 있습니다. 이 문서에 표시된 코드 샘플에서는 SQL Server 샘플 데이터베이스 AdventureWorks를 사용합니다. 코드 샘플에서는 기존 테이블을 변경하지 않도록 사용자가 먼저 생성한 테이블에 데이터를 씁니다.

BulkCopyDemoMatchingColumnsBulkCopyDemoDifferentColumns 테이블은 둘 다 AdventureWorks Production.Products 테이블을 기반으로 합니다. 이러한 테이블을 사용하는 코드 샘플에서는 데이터가 Production.Products 테이블에서 이러한 샘플 테이블 중 하나로 추가됩니다. BulkCopyDemoDifferentColumns 테이블은 샘플에서 원본 데이터의 열을 대상 테이블로 매핑하는 방법을 설명하는 경우에 사용하며 BulkCopyDemoMatchingColumns는 대부분의 다른 샘플에 사용됩니다.

일부 코드 샘플에서는 SQLServerBulkCopy 클래스 하나로 여러 테이블에 쓰는 방법을 보여 줍니다. 이러한 샘플에서 BulkCopyDemoOrderHeader 테이블과 BulkCopyDemoOrderDetail 테이블이 대상 테이블로 사용됩니다. 이러한 테이블은 AdventureWorks의 Sales.SalesOrderHeaderSales.SalesOrderDetail 테이블을 기반으로 합니다.

참고 항목

SQLServerBulkCopy 코드 샘플은 SQLServerBulkCopy를 사용하는 구문을 보여 주기 위한 용도로만 제공됩니다. 소스 테이블과 대상 테이블이 동일한 SQL Server 인스턴스에 있으면 Transact-SQL INSERT ... SELECT 문을 사용하여 데이터를 더 쉽고 빠르게 복사할 수 있습니다.

테이블 설정

코드 샘플을 올바르게 실행하는 데 필요한 테이블을 만들려면 SQL Server 데이터베이스에서 다음 TRANSACT-SQL 문을 실행해야 합니다.

USE AdventureWorks2022;
GO
  
IF EXISTS (SELECT * FROM dbo.sysobjects
 WHERE id = object_id(N'[dbo].[BulkCopyDemoMatchingColumns]')
 AND OBJECTPROPERTY(id, N'IsUserTable') = 1)  
    DROP TABLE [dbo].[BulkCopyDemoMatchingColumns]  
  
CREATE TABLE [dbo].[BulkCopyDemoMatchingColumns]([ProductID] [int] IDENTITY(1,1) NOT NULL,  
    [Name] [nvarchar](50) NOT NULL,  
    [ProductNumber] [nvarchar](25) NOT NULL,  
 CONSTRAINT [PK_ProductID] PRIMARY KEY CLUSTERED
(  
    [ProductID] ASC  
) ON [PRIMARY]) ON [PRIMARY]  
  
IF EXISTS (SELECT * FROM dbo.sysobjects
 WHERE id = object_id(N'[dbo].[BulkCopyDemoDifferentColumns]')
 AND OBJECTPROPERTY(id, N'IsUserTable') = 1)  
    DROP TABLE [dbo].[BulkCopyDemoDifferentColumns]  
  
CREATE TABLE [dbo].[BulkCopyDemoDifferentColumns]([ProdID] [int] IDENTITY(1,1) NOT NULL,  
    [ProdNum] [nvarchar](25) NOT NULL,  
    [ProdName] [nvarchar](50) NOT NULL,  
 CONSTRAINT [PK_ProdID] PRIMARY KEY CLUSTERED
(  
    [ProdID] ASC  
) ON [PRIMARY]) ON [PRIMARY]  
  
IF EXISTS (SELECT * FROM dbo.sysobjects
 WHERE id = object_id(N'[dbo].[BulkCopyDemoOrderHeader]')
 AND OBJECTPROPERTY(id, N'IsUserTable') = 1)  
    DROP TABLE [dbo].[BulkCopyDemoOrderHeader]  
  
CREATE TABLE [dbo].[BulkCopyDemoOrderHeader]([SalesOrderID] [int] IDENTITY(1,1) NOT NULL,  
    [OrderDate] [datetime] NOT NULL,  
    [AccountNumber] [nvarchar](15) NULL,  
 CONSTRAINT [PK_SalesOrderID] PRIMARY KEY CLUSTERED
(  
    [SalesOrderID] ASC  
) ON [PRIMARY]) ON [PRIMARY]  
  
IF EXISTS (SELECT * FROM dbo.sysobjects
 WHERE id = object_id(N'[dbo].[BulkCopyDemoOrderDetail]')
 AND OBJECTPROPERTY(id, N'IsUserTable') = 1)  
    DROP TABLE [dbo].[BulkCopyDemoOrderDetail]  
  
CREATE TABLE [dbo].[BulkCopyDemoOrderDetail]([SalesOrderID] [int] NOT NULL,  
    [SalesOrderDetailID] [int] NOT NULL,  
    [OrderQty] [smallint] NOT NULL,  
    [ProductID] [int] NOT NULL,  
    [UnitPrice] [money] NOT NULL,  
 CONSTRAINT [PK_LineNumber] PRIMARY KEY CLUSTERED
(  
    [SalesOrderID] ASC,  
    [SalesOrderDetailID] ASC  
) ON [PRIMARY]) ON [PRIMARY]  
  

단일 대량 복사 작업

SQL Server 대량 복사 작업을 수행하는 가장 간단한 접근 방식은 데이터베이스에 단일 작업을 수행하는 것입니다. 기본적으로 대량 복사 작업은 격리된 작업으로 수행됩니다. 복사 작업은 트랜잭션되지 않은 방식으로 수행되어 롤백할 수 없습니다.

참고 항목

오류가 발생할 때 대량 복사의 전체 또는 일부를 롤백해야 하는 경우에는 SQLServerBulkCopy에서 관리되는 트랜잭션을 사용하거나 기존 트랜잭션 내에서 대량 복사 작업을 수행할 수 있습니다.
자세한 내용은 트랜잭션 및 대량 복사 작업을 참조하세요

대량 복사 작업을 수행하는 일반적인 단계는 다음과 같습니다.

  1. 소스 서버에 연결하고 복사할 데이터를 가져옵니다. ResultSet 개체 또는 ISQLServerBulkRecord 구현에서 데이터를 검색할 수 있는 경우, 다른 원본에서 데이터를 가져올 수도 있습니다.

  2. SQLServerBulkCopy를 통해 자동으로 연결하지 않으려는 경우 대상 서버에 연결합니다.

  3. setBulkCopyOptions를 통해 필요한 속성을 설정하면서 SQLServerBulkCopy 개체를 만듭니다.

  4. 대량 삽입 작업의 대상 테이블을 나타내려면 setDestinationTableName 메서드를 호출합니다.

  5. writeToServer 메서드 중 하나를 호출합니다.

  6. 선택 사항으로 setBulkCopyOptions를 통해 속성을 업데이트하고 필요에 따라 writeToServer를 다시 호출합니다.

  7. close를 호출하거나 대량 복사 작업을 try-with-resources 문 내에 래핑합니다.

주의

소스 열과 대상 열의 데이터 형식은 일치하는 것이 좋습니다. 데이터 형식이 일치하지 않으면 SQLServerBulkCopy는 각 소스 값을 대상 데이터 형식으로 변환하려고 시도합니다. 변환을 수행하면 성능에 영향을 줄 뿐 아니라 예기치 않은 오류가 발생할 수도 있습니다. 예를 들어 double 데이터 형식은 대부분의 경우 decimal 데이터 형식으로 변환할 수 있지만 항상 그렇지는 않습니다.

예시

다음 응용 프로그램에서는 SQLServerBulkCopy 클래스를 사용하여 데이터를 로드하는 방법을 보여 줍니다. 이 예제에서는 ResultSet를 사용하여 SQL Server AdventureWorks 데이터베이스에 있는 Production.Product 테이블의 데이터를 같은 데이터베이스의 비슷한 테이블로 복사합니다.

Important

이 샘플은 테이블 설정에 설명된 대로 작업 테이블을 만들지 않은 경우 실행되지 않습니다. 이 코드는 SQLServerBulkCopy를 사용하는 구문을 보여 주는 용도로만 제공됩니다. 소스 테이블과 대상 테이블이 동일한 SQL Server 인스턴스에 있으면 Transact-SQL INSERT ... SELECT 문을 사용하여 데이터를 더 쉽고 빠르게 복사할 수 있습니다.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;

public class BulkCopySingle {
    public static void main(String[] args) {
        String connectionUrl = "jdbc:sqlserver://<server>:<port>;encrypt=true;databaseName=AdventureWorks;user=<user>;password=<password>";
        String destinationTable = "dbo.BulkCopyDemoMatchingColumns";
        int countBefore, countAfter;
        ResultSet rsSourceData;

        try (Connection sourceConnection = DriverManager.getConnection(connectionUrl);
                Connection destinationConnection = DriverManager.getConnection(connectionUrl);
                Statement stmt = sourceConnection.createStatement();
                SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(destinationConnection)) {

            // Empty the destination table.
            stmt.executeUpdate("DELETE FROM " + destinationTable);

            // Perform an initial count on the destination table.
            countBefore = getRowCount(stmt, destinationTable);

            // Get data from the source table as a ResultSet.
            rsSourceData = stmt.executeQuery("SELECT ProductID, Name, ProductNumber FROM Production.Product");

            // In real world applications you would
            // not use SQLServerBulkCopy to move data from one table to the other
            // in the same database. This is for demonstration purposes only.

            // Set up the bulk copy object.
            // Note that the column positions in the source
            // table match the column positions in
            // the destination table so there is no need to
            // map columns.
            bulkCopy.setDestinationTableName(destinationTable);

            // Write from the source to the destination.
            bulkCopy.writeToServer(rsSourceData);

            // Perform a final count on the destination
            // table to see how many rows were added.
            countAfter = getRowCount(stmt, destinationTable);
            System.out.println((countAfter - countBefore) + " rows were added.");
        }
        // Handle any errors that may have occurred.
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static int getRowCount(Statement stmt,
            String tableName) throws SQLException {
        ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
        rs.next();
        int count = rs.getInt(1);
        rs.close();
        return count;
    }
}

Transact-SQL을 사용하여 대량 복사 작업 수행

다음 예제에서는 executeUpdate 메서드를 사용하여 BULK INSERT 문을 실행하는 방법을 보여 줍니다.

참고 항목

데이터 소스의 파일 경로는 서버에 대해 상대적입니다. 대량 복사 작업이 성공하려면 서버 프로세스에서 해당 경로에 액세스할 수 있어야 합니다.

try (Connection con = DriverManager.getConnection(connectionUrl);
        Statement stmt = con.createStatement()) {
    // Perform the BULK INSERT
    stmt.executeUpdate(
            "BULK INSERT Northwind.dbo.[Order Details] " + "FROM 'f:\\mydata\\data.tbl' " + "WITH ( FORMATFILE='f:\\mydata\\data.fmt' )");
}

여러 대량 복사 작업

SQLServerBulkCopy 클래스의 단일 인스턴스를 사용하여 여러 대량 복사 작업을 수행할 수 있습니다. 복사본 간에 작업 매개 변수(예: 대상 테이블의 이름)가 변경되는 경우 다음 예에 설명된 대로 writeToServer 메서드에 대한 후속 호출 전에 업데이트해야 합니다. 명시적으로 변경하지 않는 한 모든 속성 값은 지정된 인스턴스에 대한 이전의 대량 복사 작업과 동일하게 유지됩니다.

참고 항목

SQLServerBulkCopy의 단일 인스턴스를 사용하여 여러 대량 복사 작업을 수행하는 것은 작업마다 별도의 인스턴스를 사용하는 방법보다 대개 효율적입니다.

동일한 SQLServerBulkCopy 개체를 사용하여 여러 대량 복사 작업을 수행하는 경우 각 작업에서 소스 또는 대상 정보가 동일한지 여부에 대한 제한이 없습니다. 그러나 열 연결 정보는 서버에 쓸 때마다 올바르게 설정되어 있어야 합니다.

Important

이 샘플은 테이블 설정에 설명된 대로 작업 테이블을 만들지 않은 경우 실행되지 않습니다. 이 코드는 SQLServerBulkCopy를 사용하는 구문을 보여 주는 용도로만 제공됩니다. 소스 테이블과 대상 테이블이 동일한 SQL Server 인스턴스에 있으면 Transact-SQL INSERT ... SELECT 문을 사용하여 데이터를 더 쉽고 빠르게 복사할 수 있습니다.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions;

public class BulkCopyMultiple {
    public static void main(String[] args) {
        String connectionUrl = "jdbc:sqlserver://<server>:<port>;encrypt=true;databaseName=AdventureWorks;user=<user>;password=<password>";
        String destinationHeaderTable = "dbo.BulkCopyDemoOrderHeader";
        String destinationDetailTable = "dbo.BulkCopyDemoOrderDetail";
        int countHeaderBefore, countDetailBefore, countHeaderAfter, countDetailAfter;
        ResultSet rsHeader, rsDetail;

        try (Connection sourceConnection1 = DriverManager.getConnection(connectionUrl);
                Connection sourceConnection2 = DriverManager.getConnection(connectionUrl);
                Statement stmt = sourceConnection1.createStatement();
                PreparedStatement preparedStmt1 = sourceConnection1.prepareStatement(
                        "SELECT [SalesOrderID], [OrderDate], [AccountNumber] FROM [Sales].[SalesOrderHeader] WHERE [AccountNumber] = ?;");
                PreparedStatement preparedStmt2 = sourceConnection2.prepareStatement(
                        "SELECT [Sales].[SalesOrderDetail].[SalesOrderID], [SalesOrderDetailID], [OrderQty], [ProductID], [UnitPrice] FROM "
                                + "[Sales].[SalesOrderDetail] INNER JOIN [Sales].[SalesOrderHeader] ON "
                                + "[Sales].[SalesOrderDetail].[SalesOrderID] = [Sales].[SalesOrderHeader].[SalesOrderID] WHERE [AccountNumber] = ?;");
                SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connectionUrl);) {

            // Empty the destination tables.
            stmt.executeUpdate("DELETE FROM " + destinationHeaderTable);
            stmt.executeUpdate("DELETE FROM " + destinationDetailTable);

            // Perform an initial count on the destination
            // table with matching columns.
            countHeaderBefore = getRowCount(stmt, destinationHeaderTable);

            // Perform an initial count on the destination
            // table with different column positions.
            countDetailBefore = getRowCount(stmt, destinationDetailTable);

            // Get data from the source table as a ResultSet.
            // The Sales.SalesOrderHeader and Sales.SalesOrderDetail
            // tables are quite large and could easily cause a timeout
            // if all data from the tables is added to the destination.
            // To keep the example simple and quick, a parameter is
            // used to select only orders for a particular account
            // as the source for the bulk insert.
            preparedStmt1.setString(1, "10-4020-000034");
            rsHeader = preparedStmt1.executeQuery();

            // Get the Detail data in a separate connection.
            preparedStmt2.setString(1, "10-4020-000034");
            rsDetail = preparedStmt2.executeQuery();

            // Create the SQLServerBulkCopySQLServerBulkCopy object.
            SQLServerBulkCopyOptions copyOptions = new SQLServerBulkCopyOptions();
            copyOptions.setBulkCopyTimeout(100);
            bulkCopy.setBulkCopyOptions(copyOptions);
            bulkCopy.setDestinationTableName(destinationHeaderTable);

            // Guarantee that columns are mapped correctly by
            // defining the column mappings for the order.
            bulkCopy.addColumnMapping("SalesOrderID", "SalesOrderID");
            bulkCopy.addColumnMapping("OrderDate", "OrderDate");
            bulkCopy.addColumnMapping("AccountNumber", "AccountNumber");

            // Write rsHeader to the destination.
            bulkCopy.writeToServer(rsHeader);

            // Set up the order details destination.
            bulkCopy.setDestinationTableName(destinationDetailTable);

            // Clear the existing column mappings
            bulkCopy.clearColumnMappings();

            // Add order detail column mappings.
            bulkCopy.addColumnMapping("SalesOrderID", "SalesOrderID");
            bulkCopy.addColumnMapping("SalesOrderDetailID", "SalesOrderDetailID");
            bulkCopy.addColumnMapping("OrderQty", "OrderQty");
            bulkCopy.addColumnMapping("ProductID", "ProductID");
            bulkCopy.addColumnMapping("UnitPrice", "UnitPrice");

            // Write rsDetail to the destination.
            bulkCopy.writeToServer(rsDetail);

            // Perform a final count on the destination
            // tables to see how many rows were added.
            countHeaderAfter = getRowCount(stmt, destinationHeaderTable);
            countDetailAfter = getRowCount(stmt, destinationDetailTable);

            System.out.println((countHeaderAfter - countHeaderBefore) + " rows were added to the Header table.");
            System.out.println((countDetailAfter - countDetailBefore) + " rows were added to the Detail table.");
        }
        // Handle any errors that may have occurred.
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static int getRowCount(Statement stmt,
            String tableName) throws SQLException {
        ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
        rs.next();
        int count = rs.getInt(1);
        rs.close();
        return count;
    }
}

트랜잭션 및 대량 복사 작업

대량 복사 작업은 격리된 작업이나 여러 단계 트랜잭션의 일부로 수행할 수 있습니다. 후자 옵션을 사용하면 동일한 트랜잭션 내에서 둘 이상의 대량 복사 작업을 수행할 뿐만 아니라 전체 트랜잭션을 커밋하거나 롤백하면서 다른 데이터베이스 작업(예: 삽입, 업데이트 및 삭제)을 수행할 수 있습니다.

기본적으로 대량 복사 작업은 격리된 작업으로 수행됩니다. 대량 복사 작업은 롤백할 수 없는 비트랜잭트 방식으로 이루어집니다. 오류가 발생할 때 대량 복사의 전체 또는 일부를 롤백해야 하는 경우에는 SQLServerBulkCopy에서 관리되는 트랜잭션을 사용하거나 기존 트랜잭션 내에서 대량 복사 작업을 수행할 수 있습니다.

Azure Data Warehouse용 대량 복사 확대

드라이버 버전 v8.4.1에서는 새 연결 속성 sendTemporalDataTypesAsStringForBulkCopy가 추가됩니다. 이 부울 속성은 기본적으로 true입니다.

이 연결 속성을 false로 설정하면 DATE, DATETIME, DATIMETIME2, DATETIMEOFFSET, SMALLDATETIME, TIME 데이터 형식을 문자열로 전송하는 대신 각각의 형식으로 전송합니다.

임시 데이터 형식을 해당 형식으로 보내면, 사용자가 Azure Synapse Analytics의 해당 열로 데이터를 보낼 수 있습니다. 데이터를 문자열로 변환하는 드라이버로 인해 이전에는 불가능했던 작업입니다. SQL Server에서는 시간 열에 문자열 데이터를 보낼 수 있습니다. SQL Server가 자동으로 암시적 변환을 수행하기 때문입니다. 그러나 Azure Synapse Analytics에서는 문자열 데이터를 보낼 수 없습니다.

또한 이 연결 문자열을 'false'로 설정하지 않아도 v8.4.1 이상에서는 MONEYSMALLMONEY 데이터 형식이 DECIMAL 대신 MONEY / SMALLMONEY 데이터 형식으로 전송됩니다. 그러므로 이 경우에도 해당 데이터 형식을 Azure Synapse Analytics로 대량 복사할 수 있습니다.

Azure Data Warehouse용 대량 복사 확대 제한 사항

현재 두 가지 제한 사항이 있습니다.

  1. 이 연결 속성을 false로 설정하면 드라이버는 각 시간 데이터 형식의 기본 문자열 리터럴 형식만 허용합니다. 예를 들면 다음과 같습니다.

    DATE: YYYY-MM-DD

    DATETIME: YYYY-MM-DD hh:mm:ss[.nnn]

    DATETIME2: YYYY-MM-DD hh:mm:ss[.nnnnnnn]

    DATETIMEOFFSET: YYYY-MM-DD hh:mm:ss[.nnnnnnn] [{+/-}hh:mm]

    SMALLDATETIME:YYYY-MM-DD hh:mm:ss

    TIME: hh:mm:ss[.nnnnnnn]

  2. 이 연결 속성을 false로 설정하면 대량 복사에 지정된 열 형식이 여기의 데이터 형식 매핑 차트를 따라야 합니다. 예를 들어, 이전에는 사용자가 DATE 열에 데이터를 대량 복사하도록 java.sql.Types.TIMESTAMP를 지정할 수 있었지만 이 기능을 사용하도록 설정하면 동일한 작업을 수행하도록 java.sql.Types.DATE를 지정해야 합니다.

비트랜잭트 대량 복사 작업 수행

다음 애플리케이션에서는 트랜잭션되지 않은 대량 복사 작업 중 오류가 발생할 경우 어떻게 되는지를 보여 줍니다.

이 예제에서 소스 테이블과 대상 테이블에는 ProductID라는 ID 열이 각각 포함되어 있습니다. 먼저 코드는 모든 행을 삭제한 다음 ProductID가 원본 테이블에 있는 것으로 알려진 단일 행을 삽입하여 대상 테이블을 준비합니다. 기본적으로 ID 열의 새 값이 대상 테이블의 추가된 행마다 생성됩니다. 이 예에서 옵션은 대량 로드 프로세스에서 원본 테이블의 ID 값을 대신 강제로 사용하도록 하는 연결을 열 때 설정됩니다.

대량 복사 작업은 BatchSize 속성을 10으로 설정하여 실행합니다. 작업 중 올바르지 않은 행이 발견되면 예외가 throw됩니다. 이 첫 번째 예제에서는 대량 복사 작업이 트랜잭션되지 않습니다. 오류 지점까지 복사한 모든 배치가 커밋되어, 중복 키를 포함하는 배치가 롤백되고 다른 모든 배치가 처리될 때까지 대량 복사 작업이 중지됩니다.

참고 항목

이 샘플은 테이블 설정에 설명된 대로 작업 테이블을 만들지 않은 경우 실행되지 않습니다. 이 코드는 SQLServerBulkCopy를 사용하는 구문을 보여 주는 용도로만 제공됩니다. 소스 테이블과 대상 테이블이 동일한 SQL Server 인스턴스에 있으면 Transact-SQL INSERT ... SELECT 문을 사용하여 데이터를 더 쉽고 빠르게 복사할 수 있습니다.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions;

public class BulkCopyNonTransacted {
    public static void main(String[] args) {
        String connectionUrl = "jdbc:sqlserver://<server>:<port>;encrypt=true;databaseName=AdventureWorks;user=<user>;password=<password>";
        String destinationTable = "dbo.BulkCopyDemoMatchingColumns";
        int countBefore, countAfter;
        ResultSet rsSourceData;

        try (Connection sourceConnection = DriverManager.getConnection(connectionUrl);
                Statement stmt = sourceConnection.createStatement();
                SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connectionUrl)) {

            // Empty the destination table.
            stmt.executeUpdate("DELETE FROM " + destinationTable);

            // Add a single row that will result in duplicate key
            // when all rows from source are bulk copied.
            // Note that this technique will only be successful in
            // illustrating the point if a row with ProductID = 446
            // exists in the AdventureWorks Production.Products table.
            // If you have made changes to the data in this table, change
            // the SQL statement in the code to add a ProductID that
            // does exist in your version of the Production.Products
            // table. Choose any ProductID in the middle of the table
            // (not first or last row) to best illustrate the result.
            stmt.executeUpdate("SET IDENTITY_INSERT " + destinationTable + " ON;" + "INSERT INTO " + destinationTable
                    + "([ProductID], [Name] ,[ProductNumber]) VALUES(446, 'Lock Nut 23','LN-3416'); SET IDENTITY_INSERT " + destinationTable
                    + " OFF");

            // Perform an initial count on the destination table.
            countBefore = getRowCount(stmt, destinationTable);

            // Get data from the source table as a ResultSet.
            rsSourceData = stmt.executeQuery("SELECT ProductID, Name, ProductNumber FROM Production.Product");

            // Set up the bulk copy object using the KeepIdentity option and BatchSize = 10.
            SQLServerBulkCopyOptions copyOptions = new SQLServerBulkCopyOptions();
            copyOptions.setKeepIdentity(true);
            copyOptions.setBatchSize(10);

            bulkCopy.setBulkCopyOptions(copyOptions);
            bulkCopy.setDestinationTableName(destinationTable);

            // Write from the source to the destination.
            // This should fail with a duplicate key error
            // after some of the batches have been copied.
            try {
                bulkCopy.writeToServer(rsSourceData);
            }
            catch (SQLException e) {
                e.printStackTrace();
            }

            // Perform a final count on the destination
            // table to see how many rows were added.
            countAfter = getRowCount(stmt, destinationTable);
            System.out.println((countAfter - countBefore) + " rows were added.");
        }
        // Handle any errors that may have occurred.
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static int getRowCount(Statement stmt,
            String tableName) throws SQLException {
        ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
        rs.next();
        int count = rs.getInt(1);
        rs.close();
        return count;
    }
}

트랜잭션에서 전용 대량 복사 작업 수행

기본적으로 대량 복사 작업은 트랜잭션 자체를 만들지 않습니다. 전용 대량 복사 작업을 수행하려면 연결 문자열이 있는 SQLServerBulkCopy의 새 인스턴스를 만듭니다. 이 시나리오에서는 데이터베이스가 대량 복사 작업의 각 배치를 암시적으로 커밋합니다. 대량 복사 작업에서 트랜잭션이 생성되도록 SQLServerBulkCopyOptions에서 UseInternalTransaction 옵션을 true로 설정하여 대량 복사 작업의 각 배치 이후에 커밋을 수행할 수 있습니다.

SQLServerBulkCopyOptions copyOptions = new SQLServerBulkCopyOptions();
copyOptions.setKeepIdentity(true);
copyOptions.setBatchSize(10);
copyOptions.setUseInternalTransaction(true);

기존 트랜잭션 사용

트랜잭션이 SQLServerBulkCopy 생성자의 매개 변수로 설정된 Connection 개체를 전달할 수 있습니다. 이 상황에서는 대량 복사 작업이 기존 트랜잭션에서 수행되며 트랜잭션 상태가 변경되지 않습니다. 즉, 커밋되거나 중단되지 않습니다. 따라서 애플리케이션에서 다른 데이터베이스 작업과 함께 대량 복사 작업을 하나의 트랜잭션에 포함시킬 수 있습니다. 오류가 발생하여 전체 대량 복사 작업을 롤백해야 하는 경우나 롤백할 수 있는 보다 큰 프로세스의 일부로 대량 복사를 실행해야 하는 경우, 대량 복사 작업 이후 언제든 Connection 개체에서 롤백을 수행할 수 있습니다.

이 예제의 대량 복사 작업이 더 큰 외부 트랜잭션에 포함된다는 한 가지를 제외하면 다음 응용 프로그램은 BulkCopyNonTransacted와 유사합니다. 기본 키 위반 오류가 발생하는 경우에는 전체 트랜잭션이 롤백되고 대상 테이블에 행이 추가되지 않습니다.

참고 항목

이 샘플은 테이블 설정에 설명된 대로 작업 테이블을 만들지 않은 경우 실행되지 않습니다. 이 코드는 SQLServerBulkCopy를 사용하는 구문을 보여 주는 용도로만 제공됩니다. 소스 테이블과 대상 테이블이 동일한 SQL Server 인스턴스에 있으면 Transact-SQL INSERT ... SELECT 문을 사용하여 데이터를 더 쉽고 빠르게 복사할 수 있습니다.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions;

public class BulkCopyExistingTransactions {
    public static void main(String[] args) {
        String connectionUrl = "jdbc:sqlserver://<server>:<port>;encrypt=true;databaseName=AdventureWorks;user=<user>;password=<password>";
        String destinationTable = "dbo.BulkCopyDemoMatchingColumns";
        int countBefore, countAfter;
        ResultSet rsSourceData;
        SQLServerBulkCopyOptions copyOptions;

        try (Connection sourceConnection = DriverManager.getConnection(connectionUrl);
                Connection destinationConnection = DriverManager.getConnection(connectionUrl);
                Statement stmt = sourceConnection.createStatement();
                SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(destinationConnection);) {

            // Empty the destination table.
            stmt.executeUpdate("DELETE FROM " + destinationTable);

            // Add a single row that will result in duplicate key
            // when all rows from source are bulk copied.
            // Note that this technique will only be successful in
            // illustrating the point if a row with ProductID = 446
            // exists in the AdventureWorks Production.Products table.
            // If you have made changes to the data in this table, change
            // the SQL statement in the code to add a ProductID that
            // does exist in your version of the Production.Products
            // table. Choose any ProductID in the middle of the table
            // (not first or last row) to best illustrate the result.
            stmt.executeUpdate("SET IDENTITY_INSERT " + destinationTable + " ON;" + "INSERT INTO " + destinationTable
                    + "([ProductID], [Name] ,[ProductNumber]) VALUES(446, 'Lock Nut 23','LN-3416'); SET IDENTITY_INSERT " + destinationTable
                    + " OFF");

            // Perform an initial count on the destination table.
            countBefore = getRowCount(stmt, destinationTable);

            // Get data from the source table as a ResultSet.
            rsSourceData = stmt.executeQuery("SELECT ProductID, Name, ProductNumber FROM Production.Product");

            // Set up the bulk copy object inside the transaction.
            destinationConnection.setAutoCommit(false);

            copyOptions = new SQLServerBulkCopyOptions();
            copyOptions.setKeepIdentity(true);
            copyOptions.setBatchSize(10);

            bulkCopy.setBulkCopyOptions(copyOptions);
            bulkCopy.setDestinationTableName(destinationTable);

            // Write from the source to the destination.
            // This should fail with a duplicate key error.
            try {
                bulkCopy.writeToServer(rsSourceData);
                destinationConnection.commit();
            }
            catch (SQLException e) {
                e.printStackTrace();
                destinationConnection.rollback();
            }

            // Perform a final count on the destination
            // table to see how many rows were added.
            countAfter = getRowCount(stmt, destinationTable);
            System.out.println((countAfter - countBefore) + " rows were added.");
        }
        catch (Exception e) {
            // Handle any errors that may have occurred.
            e.printStackTrace();
        }
    }

    private static int getRowCount(Statement stmt,
            String tableName) throws SQLException {
        ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
        rs.next();
        int count = rs.getInt(1);
        rs.close();
        return count;
    }
}

CSV 파일에서 대량 복사

다음 응용 프로그램에서는 SQLServerBulkCopy 클래스를 사용하여 데이터를 로드하는 방법을 보여 줍니다. 이 예제에서 CSV 파일은 SQL Server AdventureWorks 데이터베이스의 Production.Product 테이블에서 내보낸 데이터를 데이터베이스의 유사한 테이블에 복사하는 데 사용됩니다.

Important

이 샘플은 가져올 테이블 설정에 설명된 대로, 작업 테이블을 만들지 않은 경우 실행되지 않습니다.

  1. SQL Server Management Studio를 열고 SQL Server를 AdventureWorks 데이터베이스에 연결합니다.

  2. 데이터베이스를 확장하고 AdventureWorks 데이터베이스를 마우스 오른쪽 단추로 클릭한 다음, 작업데이터 내보내기를 선택합니다.

  3. 데이터 원본의 경우 SQL Server에 연결할 수 있는 데이터 원본(예: SQL Server Native Client 11.0)을 선택하고 구성을 검사한 후 다음을 선택합니다

  4. 대상에서 플랫 파일 대상을 선택하고 대상이 있는 파일 이름(예: C:\Test\TestBulkCSVExample.csv)을 입력합니다. 서식이 구분되어 있는지, 텍스트 한정자가 없는지 확인하고, 첫 번째 데이터 행에서 열 이름을 사용하도록 설정한 후, 다음을 선택합니다

  5. 전송 데이터를 지정할 쿼리 작성다음을 선택합니다. SQL 문를 입력하고 SELECT ProductID, Name, ProductNumber FROM Production.Product다음을 선택합니다.

  6. 구성을 검사합니다. 행 구분 기호는 {CR}{LF}로, 열 구분 기호는 쉼표({,})로 유지할 수 있습니다. 매핑 편집...을 선택하고 각 열에 대한 데이터 형식(예: ProductID의 경우 정수, 다른 경우 유니코드 문자열)이 올바른지 확인합니다.

  7. 마침으로 건너뛰고 내보내기를 실행합니다.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCSVFileRecord;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;

public class BulkCopyCSV {
    public static void main(String[] args) {
        String connectionUrl = "jdbc:sqlserver://<server>:<port>;encrypt=true;databaseName=AdventureWorks;user=<user>;password=<password>";
        String destinationTable = "dbo.BulkCopyDemoMatchingColumns";
        int countBefore, countAfter;

        // Get data from the source file by loading it into a class that implements ISQLServerBulkRecord.
        // Here we are using the SQLServerBulkCSVFileRecord implementation to import the example CSV file.
        try (Connection destinationConnection = DriverManager.getConnection(connectionUrl);
                Statement stmt = destinationConnection.createStatement();
                SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(destinationConnection);
                SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord("C:\\Test\\TestBulkCSVExample.csv", true);) {

            // Set the metadata for each column to be copied.
            fileRecord.addColumnMetadata(1, null, java.sql.Types.INTEGER, 0, 0);
            fileRecord.addColumnMetadata(2, null, java.sql.Types.NVARCHAR, 50, 0);
            fileRecord.addColumnMetadata(3, null, java.sql.Types.NVARCHAR, 25, 0);

            // Empty the destination table.
            stmt.executeUpdate("DELETE FROM " + destinationTable);

            // Perform an initial count on the destination table.
            countBefore = getRowCount(stmt, destinationTable);

            // Set up the bulk copy object.
            // Note that the column positions in the source
            // data reader match the column positions in
            // the destination table so there is no need to
            // map columns.
            bulkCopy.setDestinationTableName(destinationTable);

            // Write from the source to the destination.
            bulkCopy.writeToServer(fileRecord);

            // Perform a final count on the destination
            // table to see how many rows were added.
            countAfter = getRowCount(stmt, destinationTable);
            System.out.println((countAfter - countBefore) + " rows were added.");
        }
        // Handle any errors that may have occurred.
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static int getRowCount(Statement stmt,
            String tableName) throws SQLException {
        ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
        rs.next();
        int count = rs.getInt(1);
        rs.close();
        return count;
    }
}

regex 문자를 구분 기호로 사용

참고 항목

사용자 지정 구분 기호를 설정할 때 ‘|’ 같은 regex 문자인 경우 이스케이프합니다.

SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(CSVFilePath, null, "\\|", true);

CSV 파일에서 데이터로 구분 기호 대량 복사

드라이버 버전 8.4.1에는 새 SQLServerBulkCSVFileRecord.setEscapeColumnDelimitersCSV(boolean) API가 추가됩니다. true로 설정하면 다음 규칙이 적용됩니다.

  • 각 필드는 큰따옴표로 묶을 수도 있고 그렇지 않을 수도 있습니다.
  • 필드가 큰따옴표로 묶이지 않으면 필드 내부에 큰따옴표가 나타나지 않을 수 있습니다.
  • 큰따옴표 및 구분 기호를 포함하는 필드는 큰따옴표로 묶어야 합니다.
  • 필드를 큰따옴표로 묶은 경우 필드 내부에 나타나는 큰따옴표는 앞에 다른 큰따옴표를 배치하여 이스케이프해야 합니다.

Always Encrypted 열로 대량 복사

Microsoft JDBC Driver 6.0 for SQL Server부터는 Always Encrypted 열에서 대량 복사가 지원됩니다.

대량 복사 옵션과 원본 및 대상 테이블의 암호화 유형에 따라 JDBC 드라이버는 데이터를 투명하게 해독한 다음 암호화하거나 암호화된 데이터를 있는 그대로 보낼 수 있습니다. 예를 들어 암호화되지 않은 열에서 암호화된 열로 데이터를 대량 복사하는 경우 드라이버에서 데이터를 SQL Server로 보내기 전에 투명하게 해독합니다. 마찬가지로 데이터를 암호화되지 않은 열에서(또는 CSV 파일에서) 암호화된 열로 대량 복사하는 경우 드라이버에서 데이터를 SQL Server로 보내기 전에 투명하게 암호화합니다. 원본과 대상이 모두 암호화된 경우 allowEncryptedValueModifications 대량 복사 옵션에 따라 드라이버에서는 데이터를 있는 그대로 보내거나 SQL Server로 보내기 전에 데이터를 암호 해독하고 다시 암호화합니다.

자세한 내용은 아래의 allowEncryptedValueModifications 대량 복사 옵션 및 JDBC 드라이버에서 Always Encrypted 사용을 참조하세요.

Important

데이터를 CSV 파일에서 암호화된 열로 대량 복사하는 경우 SQL Server용 Microsoft JDBC Driver 6.0의 제한 사항:

날짜 및 시간 형식에는 Transact-SQL 기본 문자열 리터럴 형식만 지원됩니다

DATETIME 및 SMALLDATETIME 데이터 형식은 지원되지 않습니다

JDBC 드라이버용 대량 복사 API

SQLServerBulkCopy

다른 원본의 데이터를 사용하여 SQL Server 테이블을 효율적으로 대량 로드할 수 있습니다.

Microsoft SQL Server에는 많이 사용되는 bcp라는 명령 프롬프트 유틸리티가 있어 단일 서버인지 서버 간인지에 관계없이 테이블 간에 데이터를 이동할 수 있습니다. SQLServerBulkCopy 클래스를 사용하면 이와 유사한 기능을 제공하는 코드 솔루션을 Java로 작성할 수 있습니다. INSERT 문과 같은 다른 방법을 사용하여 데이터를 SQL Server 테이블에 로드할 수 있지만 SQLServerBulkCopy는 훨씬 더 향상된 성능을 제공합니다.

SQLServerBulkCopy 클래스는 SQL Server 테이블에만 데이터를 쓰는 데 사용할 수 있습니다. 그러나 데이터 원본은 SQL Server로 제한되지 않습니다. ResultSet 인스턴스 또는 ISQLServerBulkRecord 구현으로 데이터를 읽을 수 있는 한 모든 데이터 원본을 사용할 수 있습니다.

생성자 Description
SQLServerBulkCopy(Connection connection) SQLServerConnection의 지정된 열린 인스턴스를 사용하여 SQLServerBulkCopy 클래스의 새 인스턴스를 초기화합니다. Connection에 트랜잭션이 활성화된 경우 해당 트랜잭션 내에서 복사 작업이 수행됩니다.
SQLServerBulkCopy(String connectionURL) 지정된 connectionURL을 기반으로 SQLServerConnection의 새 인스턴스를 초기화하고 엽니다. 생성자는 SQLServerConnection을 사용하여 SQLServerBulkCopy 클래스의 새 인스턴스를 초기화합니다.
속성 설명
String DestinationTableName 서버에 있는 대상 테이블의 이름입니다.

writeToServer 호출 시 DestinationTableName이 설정되지 않은 경우, SQLServerException이 발생합니다.

DestinationTableName은 세 부분으로 구성된 이름(<database>.<owningschema>.<name>)입니다. 선택한 경우 표 이름을 데이터베이스 및 소유 스키마로 한정할 수 있습니다. 그러나 표 이름에서 밑줄("_") 또는 기타 특수 문자를 사용하는 경우, 대괄호로 감싸서 이름을 이스케이프해야 합니다. 자세한 내용은 Database Identifiers을 참조하세요.
ColumnMappings 열 매핑은 데이터 원본의 열과 대상의 열 간 관계를 정의합니다.

매핑이 정의되지 않은 경우 열은 서수 위치에 따라 암시적으로 매핑됩니다. 이렇게 하려면 원본 및 대상 스키마가 일치해야 합니다. 그렇지 않으면 예외가 발생합니다.

매핑이 비어 있지 않을 경우 데이터 원본에 있는 일부 열을 지정할 수 없으며, 매핑되지 않은 열은 무시됩니다.

이름 또는 서수로 원본 및 대상 열을 참조할 수 있습니다.
메서드 설명
void addColumnMapping(int sourceColumn, int destinationColumn) 서수를 사용하여 원본 열과 대상 열을 모두 지정하는 새 열 매핑을 추가합니다.
void addColumnMapping (int sourceColumn, String destinationColumn) 원본 열에는 서수를, 대상 열에는 열 이름을 사용하는 새로운 열 매핑을 추가합니다.
void addColumnMapping (String sourceColumn, int destinationColumn) 원본 열을 나타내기 위해 열 이름을, 대상 열을 지정하기 위해 서수를 사용하는 새로운 열 매핑을 추가합니다.
void addColumnMapping (String sourceColumn, String destinationColumn) 열 이름을 사용하여 원본 열과 대상 열을 모두 지정하는 새 열 매핑을 추가합니다.
void clearColumnMappings() 열 매핑의 내용을 지웁니다.
void close() SQLServerBulkCopy 인스턴스를 닫습니다.
SQLServerBulkCopyOptions getBulkCopyOptions() SQLServerBulkCopyOptions의 현재 세트를 검색합니다.
String getDestinationTableName() 현재 대상 표 이름을 검색합니다.
void setBulkCopyOptions(SQLServerBulkCopyOptions copyOptions) 제공된 옵션에 따라 SQLServerBulkCopy 인스턴스의 동작을 업데이트합니다.
void setDestinationTableName(String tableName) 대상 테이블의 이름을 설정합니다.
void writeToServer(ResultSet sourceData) 제공된 ResultSet의 모든 행을 SQLServerBulkCopy 개체의 DestinationTableName 속성으로 지정된 대상 테이블에 복사합니다.
void writeToServer(RowSet sourceData) 제공된 RowSet의 모든 행을 SQLServerBulkCopy 개체의 DestinationTableName 속성으로 지정된 대상 테이블에 복사합니다.
void writeToServer(ISQLServerBulkRecord sourceData) 제공된 ISQLServerBulkRecord 구현의 모든 행을 SQLServerBulkCopy 개체의 DestinationTableName 속성으로 지정된 대상 테이블에 복사합니다.

SQLServerBulkCopyOptions

writeToServer 메서드가 SQLServerBulkCopy의 인스턴스에서 작동하는 방식을 제어하는 설정의 컬렉션입니다.

생성자 Description
SQLServerBulkCopyOptions() 모든 설정에 기본값을 사용하여 SQLServerBulkCopyOptions 클래스의 새 인스턴스를 초기화합니다.

다음 옵션에 대한 Getter 및 setter가 있습니다.

옵션 설명 기본값
boolean CheckConstraints 데이터를 삽입하는 동안 제약 조건을 확인합니다. False - 제약 조건을 검사하지 않습니다
boolean FireTriggers 서버가 데이터베이스에 삽입될 행의 삽입 트리거를 실행합니다. False - 트리거가 발생하지 않습니다.
boolean KeepIdentity 소스 ID 값을 유지합니다. False - ID 값이 대상에서 지정됩니다
boolean KeepNulls 기본값에 대한 설정과 관계없이 대상 테이블에서 Null 값을 유지합니다. False - 해당하는 경우 null 값이 기본값으로 대체됩니다.
boolean TableLock 대량 복사 작업 기간에 대한 대량 업데이트 잠금을 획득합니다. False - 행 잠금이 사용됩니다.
boolean UseInternalTransaction true로 설정된 경우 트랜잭션 내에서 대량 복사 작업의 각 일괄 처리가 수행됩니다. (생성자가 지정한 대로) SQLServerBulkCopy에서 기존 연결을 사용하는 경우 SQLServerException이 발생합니다. SQLServerBulkCopy에서 전용 연결을 생성하는 경우, 트랜잭션이 생성되어 각 일괄 처리에 커밋됩니다. False - 트랜잭션 없음
int BatchSize 각 일괄 처리의 행 수입니다. 각 일괄 처리가 끝나면 일괄 처리의 행이 서버로 보내집니다.

BatchSize 행을 처리했거나 대상 데이터 원본으로 보낼 행이 더 이상 없는 경우, 일괄 처리가 완료됩니다. SQLServerBulkCopy 인스턴스가 UseInternalTransaction 옵션이 false로 설정된 상태로 선언된 경우 행은 한 번에 서버 BatchSize 행으로 보내지지만 트랜잭션 관련 작업이 수행되지 않습니다. UseInternalTransactiontrue로 설정된 경우 명시적 트랜잭션 내에서 각 행의 일괄 처리가 수행됩니다.
0 - 각 writeToServer 작업이 단일 일괄 처리임을 나타냅니다
int BulkCopyTimeout 시간 초과 이전에 작업이 완료되는 시간(초)입니다. 값이 0이면 제한이 없음을 나타냅니다. 대량 복사는 무기한 대기합니다. 60초입니다.
boolean allowEncryptedValueModifications 이 기능은 Microsoft JDBC Driver 6.0(또는 그 이상) for SQL Server에서 사용할 수 있습니다.

true로 설정된 경우 allowEncryptedValueModifications는 데이터를 암호 해독하지 않고도 테이블이나 데이터베이스 간에 암호화된 데이터를 대량 복사할 수 있도록 지원합니다. 일반적으로 애플리케이션은 데이터를 해독하지 않고 한 테이블에서 암호화된 열을 선택한(앱은 열 암호화 설정 키워드가 사용하지 않도록 설정된 상태에서 데이터베이스에 연결함) 다음, 이 옵션을 사용하여 여전히 암호돠된 데이터를 대량 복사합니다. 자세한 내용은 JDBC 드라이버에서 Always Encrypted 사용을 참조하세요.

allowEncryptedValueModifications을(를) true(으)로 설정할 시 드라이버에서 데이터가 실제로 암호화되었는지 여부 또는 동일한 암호화 형식, 알고리즘 및 키를 사용하여 올바르게 암호화되었는지 확인하지 않아 데이터베이스가 손상될 수 있으므로 주의하여 사용해야 합니다.

Getter 및 setter:

메서드 설명
boolean isCheckConstraints() 데이터가 삽입되는 동안 제약 조건을 검사할지 여부를 나타냅니다.
void setCheckConstraints(boolean checkConstraints) 데이터가 삽입되는 동안 제약 조건을 검사할지 여부를 설정합니다.
boolean isFireTriggers() 서버가 데이터베이스에 삽입될 행의 삽입 트리거를 실행할지 여부를 나타냅니다.
void setFireTriggers(boolean fireTriggers) 서버가 데이터베이스에 삽입될 행의 트리거를 실행하도록 설정할지 여부를 설정합니다.
boolean isKeepIdentity() 모든 원본 ID 값을 유지하는지 여부를 나타냅니다.
void setKeepIdentity(boolean keepIdentity) ID 값을 유지할지 여부를 설정합니다.
boolean isKeepNulls() 기본값에 대한 설정에 관계없이 대상 테이블에서 null 값을 유지할지 또는 기본값(해당하는 경우)으로 대체해야 할지 여부를 나타냅니다.
void setKeepNulls(boolean keepNulls) 기본값에 대한 설정에 관계없이 대상 테이블에서 null 값을 유지할지 또는 기본값(해당하는 경우)으로 대체해야 할지 여부를 설정합니다.
boolean isTableLock() SQLServerBulkCopy가 대량 복사 작업의 기간 동안 대량 업데이트 잠금을 획득하는지 여부를 나타냅니다.
void setTableLock(boolean tableLock) SQLServerBulkCopy가 대량 복사 작업의 기간 동안 대량 업데이트 잠금을 획득하는지 여부를 설정합니다.
boolean isUseInternalTransaction() 대량 복사 작업의 각 일괄 처리가 트랜잭션 내에서 발생하는지 여부를 나타냅니다.
void setUseInternalTranscation(boolean useInternalTransaction) 대량 복사 작업의 각 일괄 처리가 트랜잭션 내에서 발생하는지 여부를 설정합니다.
int getBatchSize() 각 일괄 처리의 행 수를 가져옵니다. 각 일괄 처리가 끝나면 일괄 처리의 행이 서버로 보내집니다.
void setBatchSize(int batchSize) 각 일괄 처리의 행 수를 설정합니다. 각 일괄 처리가 끝나면 일괄 처리의 행이 서버로 보내집니다.
int getBulkCopyTimeout() 제한 시간이 초과되기 전에 작업을 완료할 시간(초)를 가져옵니다.
void setBulkCopyTimeout(int timeout) 제한 시간이 초과되기 전에 작업을 완료할 시간(초)를 설정합니다.
boolean isAllowEncryptedValueModifications() allowEncryptedValueModifications 설정을 사용할지 사용하지 않을지 여부를 나타냅니다.
void setAllowEncryptedValueModifications(boolean allowEncryptedValueModifications) Always Encrypted 열을 포함하는 대량 복사에 사용되는 allowEncryptedValueModifications 설정을 구성합니다.

ISQLServerBulkRecord

ISQLServerBulkRecord 인터페이스를 사용하여 모든 원본(예: 파일)에서 데이터를 읽는 클래스를 만들고 SQLServerBulkCopy 인스턴스가 해당 데이터로 SQL Server 테이블을 대량 로드할 수 있게 만들 수 있습니다.

인터페이스 메서드 설명
set<Integer> getColumnOrdinals() 이 데이터 레코드에 표시되는 각 열의 서수를 가져옵니다.
String getColumnName(int column) 지정된 열의 이름을 가져옵니다.
int getColumnType(int column) 지정된 열의 JDBC 데이터 형식을 가져옵니다.
int getPrecision(int column) 지정된 열의 전체 자릿수를 가져옵니다.
object[] getRowData() 현재 행에 대한 데이터를 개체의 배열로 가져옵니다.

각 개체는 지정된 열에 대해 표시된 JDBC 데이터 형식을 나타내는 데 사용되는 Java 언어 형식과 일치해야 합니다. 자세한 내용은 JDBC 드라이버 데이터 형식 이해에서 적절한 매핑을 참조하세요.
int getScale(int column) 지정된 열에 대한 소수 자릿수를 가져옵니다.
boolean isAutoIncrement(int column) 열이 ID 열을 나타내는지 여부를 나타냅니다.
boolean next() 다음 데이터 행으로 이동합니다.

SQLServerBulkCSVFileRecord

각 줄이 데이터 행을 나타내는 구분된 파일에서 기본 Java 데이터 형식으로 읽는 데 사용할 수 있는 ISQLServerBulkRecord 인터페이스를 간단하게 구현한 것입니다.

구현 참고 및 제한 사항:

  1. 한 번에 한 줄씩 데이터를 읽기 때문에, 지정된 행에서 허용되는 최대 데이터 양은 사용 가능한 메모리로 제한됩니다.

  2. varchar(max), varbinary(max), nvarchar(max), sqlxml, ntext 등 큰 데이터 형식의 스트리밍은 지원되지 않습니다.

  3. CSV 파일에 지정된 구분 기호는 데이터의 아무 곳에도 표시되지 않아야 하며 Java 정규식에서 제한된 문자인 경우 제대로 이스케이프되어야 합니다.

  4. CSV 파일 구현에서 큰따옴표는 데이터의 일부로 처리됩니다. 예를 들어 hello,"world","hello,world" 줄은 구분 기호가 쉼표인 경우 hello, "world", "helloworld" 값을 갖는 네 개의 열이 있는 것으로 처리됩니다.

  5. 줄 바꿈 문자는 행 마침 표시로 사용되며 데이터의 어느 곳에서도 허용되지 않습니다.

생성자 Description
SQLServerBulkCSVFileRecord(String fileToParse, String encoding, String delimiter, boolean firstLineIsColumnNames) 제공된 구분 기호 및 인코딩을 사용하여 fileToParse의 각 줄을 구분 분석하는 SQLServerBulkCSVFileRecord 클래스의 새 인스턴스를 초기화합니다. firstLineIsColumnNames가 True로 설정된 경우 파일의 첫 줄은 열 이름으로 구문 분석됩니다. 인코딩이 NULL이면 기본 인코딩이 사용됩니다.
SQLServerBulkCSVFileRecord(String fileToParse, String encoding, boolean firstLineIsColumnNames) 쉼표를 구분 기호로 사용하고 제공된 인코딩을 사용하여 fileToParse의 각 줄을 구분 분석하는 SQLServerBulkCSVFileRecord 클래스의 새 인스턴스를 초기화합니다. firstLineIsColumnNames가 True로 설정된 경우 파일의 첫 줄은 열 이름으로 구문 분석됩니다. 인코딩이 NULL이면 기본 인코딩이 사용됩니다.
SQLServerBulkCSVFileRecord(String fileToParse, boolean firstLineIsColumnNames 쉼표를 구분 기호로 사용하고 기본값 인코딩을 사용하여 fileToParse의 각 줄을 구분 분석하는 SQLServerBulkCSVFileRecord 클래스의 새 인스턴스를 초기화합니다. firstLineIsColumnNames가 True로 설정된 경우 파일의 첫 줄은 열 이름으로 구문 분석됩니다.
메서드 설명
void addColumnMetadata(int positionInFile, String columnName, int jdbcType, int precision, int scale) 파일에서 지정된 열에 대한 메타데이터를 추가합니다.
void close() 파일 판독기와 관련된 모든 리소스를 해제합니다.
void setTimestampWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) 파일의 타임스탬프 데이터를 java.sql.Types.TIMESTAMP_WITH_TIMEZONE으로 구문 분석하는 형식을 설정합니다.
void setTimestampWithTimezoneFormat(String dateTimeFormat) 파일의 시간 데이터를 java.sql.Types.TIME_WITH_TIMEZONE으로 구문 분석하는 형식을 설정합니다.
void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) 파일의 시간 데이터를 java.sql.Types.TIME_WITH_TIMEZONE으로 구문 분석하는 형식을 설정합니다.
void setTimeWithTimezoneFormat(String timeFormat) 파일의 시간 데이터를 java.sql.Types.TIME_WITH_TIMEZONE으로 구문 분석하는 형식을 설정합니다.

참고 항목

JDBC 드라이버 개요