SAP HANA Development
SAP HANAでNode.jsとJavaを連携する実践ガイド|接続設定・API設計・障害対応
SAP HANAにNode.jsとJavaから接続する方法を、ドライバー選定、接続設定、トランザクション、XSJSとの違い、障害切り分けまで実務向けに解説します。
SAP HANAをバックエンドにしたアプリケーションでは、Node.jsとJavaを同じデータベースへ接続し、用途に応じてAPIやバッチを分担させる構成がよく使われます。Node.jsはHTTP APIやイベント処理、Javaは業務ロジックや既存システムとの連携に向いています。両方のアプリケーションから同じトランザクション設計と権限設計を守ることが、安定運用の前提です。
この記事では、オンプレミスのSAP HANAを対象に、接続方式の選択、最小構成の実装、接続エラーの切り分け、XSJSからの移行時に確認すべき点をまとめます。開発全体の構成を先に整理する場合は、SAP HANA開発の全体像も参照してください。
Node.jsとJavaの役割を分ける
Node.jsは、クライアントからのリクエストを受けて短時間のSQLを実行し、JSONを返すAPIに適しています。非同期I/Oを利用しやすいため、複数の外部サービスを呼び出す処理や、軽量な参照系エンドポイントを構成しやすい点が特徴です。
Javaは、複数ステップの業務処理、厳密な型定義、既存のJavaライブラリとの統合、長時間のバッチ処理に適しています。JDBC接続、コネクションプール、トランザクション境界をアプリケーション側で明確に管理できます。
同じテーブルを両方のアプリケーションが更新する場合は、更新責任をAPI層に集約します。Node.jsとJavaがそれぞれ独自の業務ルールを持つと、同じデータに対する検証やロックの動作がずれるためです。複雑なデータ加工をデータベース側に置く場合は、SQLScriptプロシージャやテーブル関数を共通の実行単位にします。設計の詳細はSAP HANA SQLScriptプロシージャの実装で確認できます。
接続方式と認証情報を設計する
Node.jsでは、SAP HANA向けの@sap/hana-clientを利用して接続します。Javaでは、SAP HANA JDBCドライバーをクラスパスに追加し、JDBC URLを使って接続します。アプリケーションの実行環境には、ドライバーのバージョン、暗号化要件、接続先ホスト名、SQLポートを一貫して設定します。
典型的な接続情報は次の要素で構成します。
- ホスト名またはIPアドレス
- SQLポート
- データベースユーザー
- パスワードまたは外部認証情報
- TLS利用時の証明書検証設定
- コネクションプールの最大数と待機時間
パスワードをソースコードへ直接記述せず、OSの保護された環境変数、デプロイメント基盤のシークレット、または安全に管理された設定ストアから注入します。開発環境と本番環境で同じユーザーを使わず、アプリケーション単位で必要最小限の権限を付与します。
Node.jsの接続処理は、リクエストごとに新しい接続を作成するのではなく、アプリケーション起動時にプールを初期化します。JavaでもDataSourceと接続プールを利用し、処理終了時にConnectionを返却します。接続数はアプリケーションインスタンス数とHANA側の同時実行量を合わせて決めます。
Node.jsからSAP HANAへ接続する
Node.jsでは、ドライバーをインストールした後、接続プールを初期化してSQLを実行します。実際のプロジェクトでは、接続情報を環境変数から読み込み、アプリケーションログへパスワードを出力しないようにします。
npm install @sap/hana-client
最小構成の例は次の形です。SQL値は文字列連結せず、パラメータとして渡します。
const hana = require('@sap/hana-client');
const pool = hana.createPool({
serverNode: process.env.HANA_HOST + ':' + process.env.HANA_PORT,
uid: process.env.HANA_USER,
pwd: process.env.HANA_PASSWORD
});
async function findCustomer(customerId) {
const connection = pool.getConnection();
try {
const result = connection.exec(
'SELECT CUSTOMER_ID, NAME FROM APP.CUSTOMER WHERE CUSTOMER_ID = ?',
[customerId]
);
return result;
} finally {
connection.close();
}
}
利用するドライバーのAPIがPromise形式かコールバック形式かは、採用したパッケージの実装に合わせます。接続の取得、SQL実行、返却の各段階で例外を記録し、接続を必ず解放します。アプリケーション停止時にはプールも明示的に終了させます。
Node.jsアプリのSQLが増えたら、SQLをルートハンドラーへ直接埋め込まず、リポジトリ層やサービス層へ分離します。入力値の検証、ページング、タイムアウト、トランザクション境界をその層で統一すると、Java側のAPIとの挙動を揃えやすくなります。
JavaからSAP HANAへ接続する
Javaでは、SAP HANA JDBCドライバーを依存関係へ追加し、DataSourceをアプリケーションサーバーまたはフレームワークの管理対象にします。接続URL、ユーザー、パスワードは外部設定から読み込みます。
String url = "jdbc:sap://" + host + ":" + port;
Properties properties = new Properties();
properties.put("user", user);
properties.put("password", password);
try (Connection connection = DriverManager.getConnection(url, properties);
PreparedStatement statement = connection.prepareStatement(
"SELECT CUSTOMER_ID, NAME FROM APP.CUSTOMER WHERE CUSTOMER_ID = ?")) {
statement.setString(1, customerId);
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
String id = resultSet.getString("CUSTOMER_ID");
String name = resultSet.getString("NAME");
}
}
}
本番では、毎回DriverManagerから直接接続する構成より、管理されたDataSourceとプールを使う構成が適しています。プールの最大接続数、接続検証、アイドル接続の有効期限、取得待ちタイムアウトを設定します。
更新処理では、setAutoCommit(false)、必要なSQL、commit()またはrollback()の順序を明確にします。複数のテーブルを更新する処理をHTTPリクエスト内で実行する場合は、トランザクションの保持時間を短くし、外部API呼び出しをデータベーストランザクションの内側に置かない設計にします。
Node.jsとJavaで共通化するデータアクセス
両方のアプリケーションで同じSQLを実行する場合、SQLの仕様を文書化します。入力パラメータ、戻り値、NULLの扱い、日時のタイムゾーン、エラーコード、ページング方式を定義しておくと、実装言語による差異を抑えられます。
特に日時型と数値型は確認が必要です。Javaの型変換、Node.jsのJavaScript Number、JSONの表現範囲が異なるため、大きな整数や高精度の小数を扱う場合は文字列または適切な専用型への変換方針を決めます。日時はUTCで保持し、画面表示時に利用者のタイムゾーンへ変換する方式が扱いやすくなります。
大量データを取得するAPIでは、全件をメモリへ読み込まず、条件検索とページングを使います。列を必要最小限に絞り、検索条件に対応するインデックスを確認します。計算ビューを公開データモデルに使う場合は、SAP HANA計算ビューの作成と使い分けも役立ちます。
XSJSとNode.jsの違いを整理する
XSJSは、SAP HANA拡張アプリケーションサービス上でサーバーサイドJavaScriptを実行するための旧来のアプリケーション方式です。HANAセッションやリクエスト処理と近い位置で動作し、既存のXSJSサービスを保守する場面で登場します。
Node.jsは汎用のJavaScriptランタイムであり、パッケージ管理、HTTPフレームワーク、テストツール、外部サービス用SDKを組み合わせてアプリケーションを構成します。SAP HANAへのアクセスは専用ドライバーを通じて行い、接続プールやエラー処理をアプリケーション側で設計します。
移行時は、次の順序で確認すると作業を分解できます。
- XSJSのエンドポイント、入力、レスポンス形式を一覧化する
- SQLと業務ルールをデータアクセス層とサービス層へ分離する
- Node.js側で認証、権限、接続プールを設定する
- 正常系、入力エラー、タイムアウト、ロールバックをテストする
- 旧サービスと新サービスの結果を比較する
ランタイムを置き換えるだけでは、セッション変数、暗黙の型変換、エラーレスポンス、トランザクションの開始位置が変わることがあります。移行前後でデータベースユーザーと権限の差も確認します。
HDIコンテナを使う開発構成
複数のアプリケーションやチームが同じHANA環境を利用する場合、テーブル、ビュー、ロールなどのデータベース成果物をアプリケーションのライフサイクルと一緒に管理します。HDIコンテナを採用する構成では、Node.jsやJavaのアプリケーションから、バインディングで渡された接続情報を利用します。
HDIコンテナの成果物管理やデプロイ設計は、SAP HANA HDIコンテナの構成と運用で整理しています。データベース成果物を手動で変更せず、開発、テスト、本番へ同じ定義を段階的にデプロイできるようにします。
オンプレミス環境で同様の分離を行う場合も、開発用スキーマ、実行用ユーザー、デプロイ用ユーザーの責任範囲を分けます。アプリケーションユーザーへ開発用のDDL権限を与えず、デプロイ処理だけが成果物を変更できるようにします。
トランザクションとエラーを扱う
HTTP APIでは、クライアントへ返すエラーと、サーバーログへ残す診断情報を分けます。SQLエラーの全文をそのまま外部へ返さず、相関IDをレスポンスとログに記録します。ログにはSQLパラメータの機密情報を含めないようにします。
トランザクション内で例外が発生した場合は、ロールバック後に接続をプールへ返します。コミット済みの処理を再実行する可能性があるAPIでは、リクエストIDや業務キーを使って冪等性を設計します。タイムアウト後にサーバー側処理が継続していないかも確認します。
Node.jsとJavaの両方で、次のテストを用意します。
- 正常な単一レコード参照
- 空の検索結果
- 不正な入力値
- 一意制約違反
- 複数更新の途中失敗
- HANAへの接続断
- 同時実行時のロック待ち
- 大量結果のページング
テストと本番の差を減らすには、接続設定だけでなく、データベース成果物、ロール、初期データ、タイムゾーンも管理対象にします。障害発生時のアプリケーションログとHANA側の監視情報を同じ相関IDで追えると、原因特定が速くなります。
接続障害を切り分ける
最初に、アプリケーションホストからHANAホストへの名前解決とネットワーク疎通を確認します。次に、接続先ホスト、SQLポート、データベースユーザー、パスワード、TLS設定を個別に確認します。接続プールの枯渇では、HANAの障害ではなく、アプリケーション側の接続返却漏れやプール上限が原因になることがあります。
エラーの分類は次のように進めます。
- DNSまたはネットワークエラーなら、ホスト名、ルーティング、ファイアウォールを確認する
- 認証エラーなら、ユーザー状態、パスワード、認証方式を確認する
- 権限エラーなら、実行ユーザーに対象オブジェクトの権限があるか確認する
- SQLエラーなら、スキーマ、オブジェクト名、パラメータ型、トランザクションを確認する
- タイムアウトなら、プール待機時間、SQL実行時間、ロック待ち、ネットワークを確認する
SAP HANAデータベースエクスプローラーは、SQLの再現、結果確認、ユーザー権限の確認に利用できます。SAP HANA cockpitは、システム状態、サービス、アラート、リソース使用状況を確認する運用画面として利用できます。アプリケーション側では、接続取得時間、SQL実行時間、結果変換時間を分けて計測します。
運用前の確認項目
本番公開前には、接続情報を安全に配布できること、アプリケーションユーザーの権限が最小限であること、接続プールが負荷に耐えることを確認します。アプリケーションインスタンスを増やした場合に、HANAへの接続数が想定外に増えない設計も必要です。
データベース変更は、テーブルやビューの依存関係を確認してからデプロイします。ロールバック手順、バックアップ方針、監視項目、障害時の連絡経路を事前に決めます。パフォーマンス問題がある場合は、アプリケーションの処理時間だけでなく、SQL、実行計画、ロック、ネットワーク転送量を分けて調べます。
開発者向けのテストと障害解析の手順は、SAP HANAアプリケーションのテストとデバッグにまとめています。Node.jsとJavaを別々に評価するのではなく、同じ業務シナリオを両方の実装で再現し、結果、性能、障害時の復旧動作を比較することが重要です。