Skip to content

11.5 JDBC

Machbase JDBC 드라이버는 Java 8을 기준으로 JDBC 4.2 핵심 API를 제공합니다. 표준 JDBC API로 서버에 연결하고 PreparedStatement, 타입 지정 조회와 바인딩, 데이터베이스 메타데이터, 로컬 트랜잭션과 커넥션 풀을 사용할 수 있습니다.

항목
Java 바이트코드 기준Java 8
드라이버가 보고하는 JDBC 버전4.2
드라이버 버전3.0.0
JDBC URLjdbc:machbase://<host-list>/[database]
Driver.jdbcCompliant()false

jdbcCompliant()false는 JDBC 4.2 API 지원 여부가 아니라 SQL-92 Entry Level 전체 지원 여부를 나타냅니다. 애플리케이션에서는 필요한 선택 기능을 DatabaseMetaData의 기능 메서드로 확인합니다.

다중 데이터베이스

URL 경로 또는 database 연결 속성으로 초기 데이터베이스를 지정할 수 있습니다.

String url = "jdbc:machbase://127.0.0.1:5656/factory_a";
Connection conn = DriverManager.getConnection(url, "APP_A", password);

System.out.println(conn.getCatalog());
conn.setCatalog("FACTORY_A");

getCatalog()setCatalog()는 서버 현재 데이터베이스와 동기화됩니다. URL 경로와 설정 속성을 동시에 지정하면 값이 같아야 하며, JDBC 메타데이터에서 카탈로그는 데이터베이스, 스키마는 소유자입니다. pooled 연결은 반환 시 초기 카탈로그로 복원되는지 확인하고, 준비된 문장과 append 핸들은 생성 시점 데이터베이스에 고정된다는 점을 고려합니다.

드라이버 설치

JAR 파일 사용

Machbase 설치 디렉터리의 machbase.jar를 classpath에 추가합니다.

ls -l "$MACHBASE_HOME/lib/machbase.jar"
javac -classpath ".:$MACHBASE_HOME/lib/machbase.jar" MyApp.java
java -classpath ".:$MACHBASE_HOME/lib/machbase.jar" MyApp

JAR에는 META-INF/services/java.sql.Driver가 포함되어 있습니다. JDBC 4.0 이후 환경에서는 Class.forName("com.machbase.jdbc.MachDriver")를 호출하지 않아도 드라이버가 자동으로 등록됩니다. 기존 애플리케이션의 명시적 호출은 그대로 사용할 수 있습니다.

Maven

<dependency>
    <groupId>com.machbase</groupId>
    <artifactId>machjdbc</artifactId>
    <version>8.0.2</version>
</dependency>

Gradle

dependencies {
    implementation 'com.machbase:machjdbc:8.0.2'
}

배포 산출물 버전은 Maven Central에서 확인합니다. 드라이버가 런타임 메타데이터로 반환하는 3.0.0과 배포 산출물 버전은 서로 다른 버전 체계입니다.

서버에 연결

사용자 이름과 비밀번호는 소스 코드에 기록하지 않고 환경 변수나 비밀 관리 시스템으로 전달합니다.

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

String url = "jdbc:machbase://127.0.0.1:5656/machbasedb";

Properties properties = new Properties();
properties.setProperty("user", "SYS");
properties.setProperty("password", System.getenv("MACHBASE_PASSWORD"));

try (Connection connection =
         DriverManager.getConnection(url, properties)) {
    // SQL을 실행합니다.
}

연결 옵션

연결 옵션은 Properties 또는 URL 쿼리 문자열로 지정합니다. randomHostProperties에서 지정하거나 다중 호스트 URL의 ^ 구분자를 사용합니다.

옵션설명
user, password비밀번호 인증 정보
TIMEZONE세션 타임존. +0900 형식을 사용합니다.
randomHost호스트 목록에서 첫 연결 대상을 무작위로 선택합니다.
maxStatements풀링 연결의 최대 캐시 Statement 수
CONNECTION_TIMEOUT소켓 연결 시간 초과(초). 0은 제한 없음입니다.
SOCKET_TIMEOUT소켓 읽기 시간 초과(초). 0은 제한 없음입니다.
characterEncoding클라이언트 문자 인코딩
AUTH_MODEPASSWORD 또는 CHALLENGE
AUTH_SIG_SCHEMEECDSA, RSA_PKCS1_V15, RSA_PSS
AUTH_KEY_FILEPEM 개인키 파일 경로
String url =
    "jdbc:machbase://127.0.0.1:5656/machbasedb?TIMEZONE=+0900";

다중 호스트 연결

Machbase 8.7.0 JDBC 드라이버는 하나의 URL에 여러 호스트를 지정할 수 있습니다.

선택 방식지정 방법동작
순차 선택호스트를 ,로 구분URL에 작성한 순서대로 연결을 시도합니다.
무작위 시작호스트를 ^로 구분호스트 목록에서 첫 연결 대상을 무작위로 선택합니다.
무작위 시작PropertiesrandomHost=true 지정,로 구분한 목록에서 첫 연결 대상을 무작위로 선택합니다.

다음 URL은 db1 연결에 실패하면 db2에 연결을 시도합니다.

String url =
    "jdbc:machbase://db1.example.com:5656,db2.example.com:5656/" +
    "machbasedb?CONNECTION_TIMEOUT=5";

^ 구분자를 사용하면 첫 연결 대상을 무작위로 선택합니다.

String url =
    "jdbc:machbase://db1.example.com:5656^db2.example.com:5656/" +
    "machbasedb?CONNECTION_TIMEOUT=5";

randomHost 설정 속성을 사용하려면 ,로 호스트를 구분합니다.

Properties properties = new Properties();
properties.setProperty("randomHost", "true");

String url =
    "jdbc:machbase://db1.example.com:5656,db2.example.com:5656/" +
    "machbasedb?CONNECTION_TIMEOUT=5";
  • ,^ 구분자를 하나의 URL에서 함께 사용할 수 없습니다.
  • 연결 refused, 연결 시간 초과, 소켓 오류 등 연결 단계의 I/O 오류가 발생하면 다음 호스트로 연결을 시도합니다. 모든 호스트가 실패하면 DriverManager.getConnection()SQLException을 반환합니다.
  • CONNECTION_TIMEOUT은 호스트별 연결 시도에 적용됩니다. 따라서 전체 연결 대기 시간은 호스트 수와 각 호스트의 응답 시간에 따라 길어질 수 있습니다.
  • SOCKET_TIMEOUT은 연결된 소켓의 읽기 대기 시간을 제한하며 호스트 선택 순서를 변경하지 않습니다.

다중 호스트 전환은 새 연결 또는 재연결 과정의 소켓 연결에 적용됩니다. 연결이 끊긴 뒤 자동 reconnect가 성공해도 이전 Statement, PreparedStatement와 ResultSet은 재사용하지 않습니다. 진행 중이던 SQL의 성공 여부나 안전한 재실행을 보장하지 않으므로, 활성 트랜잭션에서 연결 오류가 발생하면 연결을 폐기하고 업무의 멱등성 정책에 따라 전체 트랜잭션을 다시 실행합니다.

AUTH KEY 인증

공개키 기반 challenge 인증에서는 비밀번호 대신 로컬 개인키로 서버 challenge에 서명합니다.

Properties properties = new Properties();
properties.setProperty("user", "app_user");
properties.setProperty("AUTH_MODE", "CHALLENGE");
properties.setProperty("AUTH_SIG_SCHEME", "ECDSA");
properties.setProperty(
    "AUTH_KEY_FILE", "/opt/machbase/keys/app_user_ecdsa.pem");

Connection connection = DriverManager.getConnection(
    "jdbc:machbase://127.0.0.1:5656/machbasedb", properties);
  • AUTH_MODE=CHALLENGE에서는 password를 인증에 사용하지 않습니다.
  • AUTH_KEY_FILE은 필수입니다.
  • AUTH_SIG_SCHEME을 생략하면 키 종류에 맞는 기본 서명 방식을 선택합니다.
  • POSIX 환경에서는 개인키 파일 권한을 600으로 제한합니다.

빠른 시작

다음 예제는 LOG 테이블에 값을 입력하고 다시 조회합니다.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

public class JdbcQuickStart {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.setProperty("user", "SYS");
        properties.setProperty(
            "password", System.getenv("MACHBASE_PASSWORD"));

        try (Connection connection = DriverManager.getConnection(
                 "jdbc:machbase://127.0.0.1:5656/machbasedb",
                 properties);
             Statement statement = connection.createStatement()) {
            statement.execute(
                "CREATE LOG TABLE jdbc_sensor " +
                "(ts DATETIME, name VARCHAR(40), value DOUBLE)");

            try (PreparedStatement insert = connection.prepareStatement(
                     "INSERT INTO jdbc_sensor VALUES (?, ?, ?)")) {
                insert.setLong(1, System.currentTimeMillis() * 1_000_000L);
                insert.setString(2, "sensor-1");
                insert.setDouble(3, 25.3);
                insert.executeUpdate();
            }

            try (ResultSet result = statement.executeQuery(
                     "SELECT name, value FROM jdbc_sensor")) {
                while (result.next()) {
                    System.out.printf("%s %.1f%n",
                        result.getString("NAME"),
                        result.getDouble("VALUE"));
                }
            }
        }
    }
}

DATETIME에 epoch 나노초 값을 전달할 때는 long을 사용합니다. 예제의 테이블이 이미 존재하면 CREATE LOG TABLE을 생략하거나 다른 이름을 사용합니다.

INSERT 결과 ROWID

Standard Edition에서 단일 INSERT ... VALUES가 성공하면 JDBC 표준 generated keys API로 입력된 행의 ROWID를 확인할 수 있습니다.

String sql = "INSERT INTO jdbc_sensor VALUES (?, ?, ?)";
try (PreparedStatement insert = connection.prepareStatement(
         sql, Statement.RETURN_GENERATED_KEYS)) {
    insert.setLong(1, System.currentTimeMillis() * 1_000_000L);
    insert.setString(2, "sensor-2");
    insert.setDouble(3, 26.1);
    insert.executeUpdate();

    try (ResultSet keys = insert.getGeneratedKeys()) {
        if (keys.next()) {
            java.sql.RowId rowId = keys.getRowId("ROWID");
        }
    }
}

결과는 ROWID 컬럼 하나와 최대 한 행으로 구성됩니다. 반환할 ROWID가 없으면 빈 ResultSet입니다. 지원 여부는 DatabaseMetaData.supportsGetGeneratedKeys()로 확인합니다. 배치, Append, INSERT ... SELECT, UPSERT의 차이는 ROWID와 INSERT 결과 ID를 참고하십시오.

버전 확인

import java.sql.DatabaseMetaData;

DatabaseMetaData metadata = connection.getMetaData();

System.out.println(metadata.getDriverName());
System.out.println(metadata.getDriverVersion());
System.out.println(metadata.getJDBCMajorVersion()); // 4
System.out.println(metadata.getJDBCMinorVersion()); // 2

관련 문서

문서내용
PreparedStatement와 타입매개변수 메타데이터, 이름 기반 bind, SQLType, NULL과 타입 변환
ResultSet, Statement와 LOBtyped 조회, 스트림, LOB, 시간 초과와 자원 관리
트랜잭션과 커넥션 풀Standard 로컬 트랜잭션, DataSource와 연결 풀
DatabaseMetaData테이블, 컬럼, 키, 인덱스와 기능 조회
Append APIMachStatement 기반 고속 입력
마이그레이션과 문제 해결이전 드라이버 전환, 미지원 기능과 오류 처리
최근 업데이트