Hologres は、Java Database Connectivity (JDBC) など、PostgreSQL と完全に互換性のある接続インターフェイスを提供しています。これらのインターフェイスを使用して、SQL クライアントツールを Hologres に接続し、データ開発を行うことができます。このトピックでは、JDBC を使用して Hologres に接続し、データ開発を行う方法について説明します。
注意事項
-
JDBC 接続を介して Hologres にデータを書き込むには、PostgreSQL JDBC Driver 42.3.2 以降を使用します。
-
データ書き込みのパフォーマンス テストには、VPC ネットワークを使用します。パブリックネットワークでは、パフォーマンス テストの目標を達成できません。
-
Hologres は単一トランザクションでの複数回の書き込みをサポートしていません。そのため、
autoCommitをtrueに設定します。JDBC の autoCommit のデフォルト値は true です。コード内でコミット操作を明示的に呼び出さないでください。ERROR: INSERT in transaction is not supported nowエラーが発生した場合は、以下に示すようにautoCommitをtrueに設定します。Connection conn = DriverManager.getConnection(url, user, password); conn.setAutoCommit(true);
JDBC を使用した Hologres への接続
JDBC を使用して Hologres に接続するには、次の手順を実行します。
-
構成のダウンロード
ほとんどのクライアントツールには、組み込みの PostgreSQL ドライバーが含まれています。利用可能な場合は、組み込みドライバーを使用します。利用できない場合は、ドライバーをダウンロードしてインストールします。
PostgreSQL ドライバーを使用するには、公式サイトにアクセスして PostgreSQL JDBC Driver をダウンロードします。バージョン 42.3.2 以降を使用してください。最新バージョンの JDBC ドライバーを使用することを推奨します。ダウンロード後、次の依存関係を Maven リポジトリに追加します。
<dependencies> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.3.2</version> </dependency> </dependencies> -
Hologres への接続
-
次の接続文字列を使用して Hologres に接続します。
jdbc:postgresql://{ENDPOINT}:{PORT}/{DBNAME}?user={ACCESS_ID}&password={ACCESS_KEY} -
次の表にパラメーターを示します。
パラメーター
説明
ENDPOINT
Hologres インスタンスのネットワーク エンドポイントとポート。
Hologres コンソールに移動します。左側のナビゲーションウィンドウで、Instances をクリックします。対象のインスタンスをクリックします。Instance Details ページの Network Information セクションで、エンドポイントとポートを確認します。
重要ご利用のコードが実行されるネットワーク環境に対応するエンドポイントとポートを選択してください。そうしないと、接続に失敗します。
PORT
DBNAME
Hologres で作成されたデータベースの名前。
ACCESS_ID
現在のアカウントのユーザー名。
認証情報の漏洩のリスクを減らすために、環境変数を使用して認証情報を指定することを推奨します。詳細については、このトピックの後半の例をご参照ください。
ACCESS_KEY
現在のアカウントのログインパスワードです。
認証情報を指定するには、環境変数を使用することを推奨します。これにより、漏洩のリスクを低減できます。詳細については、「この Topic の後半の例」をご参照ください。
-
Hologres に接続する際の次の推奨事項に注意してください。
-
JDBC URL に ApplicationName パラメーターを追加します。このパラメーターはオプションです。ApplicationName に基づいて、スロークエリチェックリストでリクエストを送信するアプリケーションをすばやく特定するのに役立ちます。次のコードは接続文字列を示しています。
jdbc:postgresql://{ENDPOINT}:{PORT}/{DBNAME}?user={ACCESS_ID}&password={ACCESS_KEY}&ApplicationName={APPLICATION_NAME} -
JDBC URL に
reWriteBatchedInserts=true構成を追加します。これにより、システムはジョブをバッチで送信してパフォーマンスを向上させることができます。次のコードは接続文字列を示しています。jdbc:postgresql://{ENDPOINT}:{PORT}/{DBNAME}?ApplicationName={APPLICATION_NAME}&reWriteBatchedInserts=true -
Prepared Statement モードを使用してデータの読み書きを行うと、スループットが向上します。
-
Hologres で外部テーブルの自動ロードを有効にすると、MaxCompute プロジェクト名が Hologres 内の同じ名前のスキーマに自動的にマッピングされます。このようなスキーマ内の外部テーブルを直接クエリする場合は、JDBC URL に
currentSchemaパラメーターを追加して、対応する MaxCompute プロジェクトにマッピングします。次のコードは接続文字列の例を示しています。jdbc:postgresql://{ENDPOINT}:{PORT}/{DBNAME}?currentSchema={SCHEMA_NAME}&user={ACCESS_ID}&password={ACCESS_KEY}&ApplicationName={APPLICATION_NAME} -
認証情報の漏洩のリスクを減らすために、環境変数を使用してユーザー名とパスワードを指定します。たとえば、Linux システムでは、bash_profile ファイルに次のコマンドを追加して環境変数を構成できます。
export ALIBABA_CLOUD_USER=<ACCESS_ID> export ALIBABA_CLOUD_PASSWORD=<ACCESS_KEY>
-
-
次のコードは接続例を示しています。
public class HologresTest { private void jdbcExample() throws SQLException { String user= System.getenv("ALIBABA_CLOUD_USER"); String password = System.getenv("ALIBABA_CLOUD_PASSWORD"); String url = String.format("jdbc:postgresql://{ENDPOINT}:{PORT}/{DBNAME}?currentSchema={SCHEMA_NAME}&user=%s&password=%s", user, password); try (Connection conn = DriverManager.getConnection(url)) { try (Statement st = conn.createStatement()) { String sql = "SELECT * FROM table where xxx limit 100"; try (ResultSet rs = st.executeQuery(sql)) { while (rs.next()) { // データテーブルの最初の列から値を取得します。 String c1 = rs.getString(1); } } } } } private void jdbcPreparedStmtExample() throws SQLException { String user= System.getenv("ALIBABA_CLOUD_USER"); String password = System.getenv("ALIBABA_CLOUD_PASSWORD"); String url = String.format("jdbc:postgresql://{ENDPOINT}:{PORT}/{DBNAME}?currentSchema={SCHEMA_NAME}&user=%s&password=%s", user, password); try (Connection conn = DriverManager.getConnection(url)) { String sql = "insert into test values" + "(?, ?), " + "(?, ?), " + "(?, ?), " + "(?, ?), " + "(?, ?), " + "(?, ?), " + "(?, ?), " + "(?, ?), " + "(?, ?), " + "(?, ?)"; try (PreparedStatement st = conn.prepareStatement(sql)) { for (int i = 0; i < 10; ++i) { for (int j = 0; j < 2 * 10; ++j) { st.setString(j + 1, UUID.randomUUID().toString()); } System.out.println("affected row => " + st.executeUpdate()); } } } } }
-
JDBC を使用した開発
JDBC を使用して Hologres に接続した後、標準的なステートメントを使用して Hologres で開発を行うことができます。これには、データの書き込みと読み取りが含まれます。
-
データの書き込み
JDBC の Statement または Prepared Statement モードを使用してデータを書き込むことができます。Prepared Statement モードを使用し、バッチサイズを 256 の倍数に設定することを推奨します。推奨される最小バッチサイズは 256 です。Prepared Statement モードでは、サーバー側で SQL コンパイル結果がキャッシュされます。これにより、書き込みレイテンシーが短縮され、スループットが向上します。
次の例は、Prepared Statement モードでデータを書き込む方法を示しています。
-
Prepared Statement モードを使用してデータをバッチで書き込みます。次のコードは例を示しています。
/*Prepared Statement モードでデータをバッチで書き込みます。*/ /*この例では、バッチサイズは 256 です。*/ private static void WriteBatchWithPreparedStatement(Connection conn) throws Exception { try (PreparedStatement stmt = conn.prepareStatement("insert into test_tb values (?,?,?,?)")) { int batchSize = 256; for (int i = 0; i < batchSize; ++i) { stmt.setInt( 1, 1000 + i); stmt.setString( 2, "1"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date parsedDate = dateFormat.parse("1990-11-11 00:00:00"); stmt.setTimestamp( 3, new java.sql.Timestamp(parsedDate.getTime())); stmt.setDouble( 4 , 0.1 ); stmt.addBatch(); } stmt.executeBatch(); } } -
Prepared Statement モードでデータを書き込む際、PostgreSQL の
INSERT ON CONFLICT機能を使用して既存データを更新または上書きすることもできます。次のコードは例を示しています。説明INSERT ON CONFLICT ステートメントを使用する場合、宛先テーブルにはプライマリキーが必要です。
private static void InsertOverwrite(Connection conn) throws Exception { try (PreparedStatement stmt = conn.prepareStatement("insert into test_tb values (?,?,?,?), (?,?,?,?), (?,?,?,?), (?,?,?,?), (?,?,?,?), (?,?,?,?) on conflict(pk) do update set f1 = excluded.f1, f2 = excluded.f2, f3 = excluded.f3")) { int batchSize = 6; for (int i = 0; i < batchSize; ++i) { stmt.setInt(i * 4 + 1, i); stmt.setString(i * 4 + 2, "1"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date parsedDate = dateFormat.parse("1990-11-11 00:00:00"); stmt.setTimestamp(i * 4 + 3, new java.sql.Timestamp(parsedDate.getTime())); stmt.setDouble(i * 4 + 4, 0.1); } int affected_rows = stmt.executeUpdate(); System.out.println("affected rows => " + affected_rows); } }
-
-
データのクエリ
データが書き込まれた後、それをクエリできます。必要に応じて、既存のテーブルからデータをクエリすることもできます。
Druid 接続プールの構成
-
注意事項
-
keepAlive=trueを設定して、接続を再利用し、短命な接続を回避します。 -
Hologres に接続するには、Druid 1.1.12 以降を使用します。
-
Druid バージョン 1.2.12 から 1.2.21 には、
connectTimeoutとsocketTimeoutパラメーターが指定されていない場合、デフォルトで 10 秒になるという問題があります。同様の問題が発生した場合は、Druid のバージョンをアップグレードしてください。
-
-
Druid 接続プールの構成
説明initialSize、minIdle、および maxActive は、ご利用のインスタンスサイズとビジネス要件に基づいて設定します。
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- jdbc_url は Hologres インスタンスのエンドポイント URL です。URL はコンソールのインスタンス構成ページから取得できます。 --> <property name="url" value="${jdbc_url}" /> <!-- jdbc_user は Hologres インスタンスのユーザーアカウントの AccessKey ID です。 --> <property name="username" value="${jdbc_user}" /> <!-- jdbc_password は Hologres インスタンスのユーザーアカウントに対応する AccessKey Secret です。 --> <property name="password" value="${jdbc_password}" /> <!-- 接続プールの初期サイズ、最小接続数、および最大接続数を構成します。 --> <property name="initialSize" value="5" /> <property name="minIdle" value="10" /> <property name="maxActive" value="20" /> <!-- 接続待機のタイムアウト期間を構成します。 --> <property name="maxWait" value="60000" /> <!-- アイドル接続の検出とクローズの間隔を構成します。単位: ミリ秒。 --> <property name="timeBetweenEvictionRunsMillis" value="2000" /> <!-- プール内の接続の最小生存時間を構成します。単位: ミリ秒。 --> <property name="minEvictableIdleTimeMillis" value="600000" /> <property name="maxEvictableIdleTimeMillis" value="900000" /> <property name="validationQuery" value="select 1" /> <property name="testWhileIdle" value="true" /> <!-- プールから接続が取得されるときに、接続の有効性をチェックするかどうかを構成します。true: 毎回チェックします。false: チェックしません。 --> <property name="testOnBorrow" value="false" /> <!-- 接続がプールに返されるときに、接続の有効性をチェックするかどうかを構成します。true: 毎回チェックします。false: チェックしません。 --> <property name="testOnReturn" value="false" /> <property name="keepAlive" value="true" /> <property name="phyMaxUseCount" value="100000" /> <!-- 監視と統計のインターセプトのためのフィルターを構成します。 --> <property name="filters" value="stat" /> </bean>
パフォーマンスチューニングのベストプラクティス
JDBC を使用する際にパフォーマンスを向上させるには、次の項目に注意してください。
-
ネットワークオーバーヘッドを回避するために、パブリックネットワークではなく VPC ネットワークを使用します。
-
JDBC ドライバーを使用してデータを書き込む際、JDBC URL に reWriteBatchedInserts=true 構成を追加します。これにより、システムはジョブをバッチで送信してパフォーマンスを向上させることができます。テストでは、バッチサイズを 256 の倍数に設定すると、より良い結果が得られることが示されています。推奨される最小バッチサイズは 256 です。Hologres Holo Client を使用することもできます。これはバッチ処理を自動的に処理します。
jdbc:postgresql://{ENDPOINT}:{PORT}/{DBNAME}?ApplicationName={APPLICATION_NAME}&reWriteBatchedInserts=true -
Prepared Statement モードを使用します。このモードでは、サーバー側で SQL コンパイル結果がキャッシュされます。これにより、書き込みレイテンシーが短縮され、スループットが向上します。
JDBC を使用した GUC パラメーターの構成
セッションレベルで Grand Unified Configuration (GUC) パラメーターを設定する必要がある場合があります。GUC パラメーターの詳細については、「GUC パラメーター」をご参照ください。GUC パラメーターを設定するには、次の方法を使用することを推奨します。この例は、セッションレベルの statement_timeout パラメーターを 12345 ミリ秒に、セッションレベルの idle_in_transaction_session_timeout パラメーターを 12345 ミリ秒に設定する方法を示しています。
import org.postgresql.PGProperty;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class gucdemo {
public static void main(String[] args) {
// Hologres インスタンスのエンドポイントを設定します。
String hostname = "hgpostcn-cn-xxxx-cn-hangzhou.hologres.aliyuncs.com";
// Hologres インスタンスのポートを設定します。
String port = "80";
// 接続するデータベースの名前を設定します。
String dbname = "demo";
String jdbcUrl = "jdbc:postgresql://" + hostname + ":" + port + "/" + dbname;
Properties properties = new Properties();
// データベース接続のユーザー名を設定します。
properties.setProperty("user", "xxxxx");
// データベース接続のパスワードを設定します。
properties.setProperty("password", "xxxx");
// GUC パラメーターを設定します。
PGProperty.OPTIONS.set(properties,"--statement_timeout=12345 --idle_in_transaction_session_timeout=12345");
try {
Class.forName("org.postgresql.Driver");
Connection connection = DriverManager.getConnection(jdbcUrl, properties);
PreparedStatement preparedStatement = connection.prepareStatement("show statement_timeout" );
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
ResultSetMetaData rsmd = resultSet.getMetaData();
int columnCount = rsmd.getColumnCount();
Map map = new HashMap();
for (int i = 0; i < columnCount; i++) {
map.put(rsmd.getColumnName(i + 1).toLowerCase(), resultSet.getObject(i + 1));
}
System.out.println(map);
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
JDBC ベースのロードバランシング
V1.3 以降、Hologres では JDBC で複数の読み取り専用セカンダリ インスタンスを構成して、シンプルなロードバランシングをサポートできます。詳細については、「JDBC ベースのロードバランシング」をご参照ください。