PostgreSQLのデフォルトスキーマをJDBC接続で指定する方法

当ページのリンクには広告が含まれています。
PostgreSQLでJDBC接続文字列のcurrentSchemaを使い、SQLを修正せずデフォルトスキーマを一括指定する方法を解説

PostgreSQLのJDBC接続でデフォルトスキーマを指定するには接続URLへcurrentSchemaを追加します。例えばこんな感じです。

jdbc:postgresql://localhost:5432/mydb?currentSchema=app_schema

この設定はSELECT * FROM test; のようにスキーマ名を省略したSQLへ適用されます。public.testのようにスキーマ名を直接書いているSQLは切り替わりません。

既存システムのSQLを修正せず接続先のスキーマだけを変更したい場合に使えます。

PostgreSQLの検証環境をDockerで用意する方法はこちらもどうぞ。

目次

なぜスキーマを一括指定したいのか

PostgreSQLで何も設定せずに下記のSQLを発行すると、デフォルトでpublicスキーマが参照されます。

SQL
SELECT * FROM test;

これは実質的に以下と同じ動作です。

SQL
SELECT * FROM public.test;

PostgreSQLの標準的なsearch_pathは通常"$user", publicです。接続ユーザーと同名のスキーマが存在しない一般的な環境では、結果としてpublicが参照されます。

リプレース時によくある要件

実務でのリプレース案件だと、こんな要件が出てきます。

  • デフォルトのpublicスキーマではなく専用スキーマ(例:app_schema)を用意したい。
  • テーブルやビューの構成は既存と全く同じにする。
  • 既存のSQL文は変更せずにそのまま流用したい。

SQLファイルが数百・数千あるケースで手動スキーマ名追記は現実的ではありませんし、修正漏れのリスクも高いですよね。

そこで使えるのがJDBC接続時のスキーマ指定です。

JDBC接続文字列で解決する方法

currentSchemaパラメータとは

PostgreSQL公式のJDBCドライバーにはcurrentSchemaというパラメータが用意されています。

currentSchema (String) Default null Specify the schema (or several schema separated by commas) to be set in the search-path. This schema will be used to resolve unqualified object names used in statements over this connection.

Initializing the Driver | pgJDBC

要約すると「指定したスキーマが、スキーマ名を省略したオブジェクト名の解決に使われる」ということです。

接続時にcurrentSchema=app_schemaと指定すれば、アプリ内のすべてのSQL文でスキーマ名が省略されている場合に自動的にapp_schemaを参照してくれます。指定がない場合はPostgreSQLのデフォルトであるpublicが使われます。

適用されるケース・されないケース

公式ドキュメントにある非修飾オブジェクト名の解決という点が重要です。SQL文でスキーマ名をハードコーディングしている場合はcurrentSchemaの指定に関係なく、そちらが優先されます。

ケース説明適用
スキーマ名なしのSQLSELECT * FROM test;✅ 適用される
スキーマ名ありのSQL(public)SELECT * FROM public.test;❌ 適用されない
スキーマ名ありのSQL(別スキーマ)SELECT * FROM app_schema.test;❌ 適用されない

設定方法(jdbc.diconの例)

S2JTAやSeasar2を利用している場合jdbc.diconなどの接続設定ファイルを以下のように変更します。

jdbc.dicon – 変更前
jdbc:postgresql://localhost:5432/mydb
jdbc.dicon – 変更後
jdbc:postgresql://localhost:5432/mydb?currentSchema=app_schema

たったこれだけです。

動作イメージ

設定後にアプリケーションから下記のSQLを発行すると、

SQL
SELECT * FROM test;

PostgreSQL内部では以下のように解釈されます。

SQL
SELECT * FROM app_schema.test;

既存のSQL文を一切変更せずにスキーマ切り替えが完了します。

currentSchemaとsearch_pathの違い

currentSchemaはJDBC接続向けの設定です。psqlで一時的にスキーマを切り替えたい場合や接続ユーザーごとに同じ設定を継続して使いたい場合はSET search_pathALTER ROLEを使います。

どの方法もスキーマ名を省略したテーブルやビューを検索する順番を指定するものです。設定が適用される範囲とタイミングが異なります。

方法適用範囲設定例向いているケース
JDBCのcurrentSchemaJDBC接続ごと?currentSchema=app_schemaアプリケーション単位で切り替えたい
SET search_path現在のセッションSET search_path TO app_schema, public;psqlでの一時確認や処理単位で切り替えたい
ALTER ROLE ... SET対象ユーザーの新しい接続ALTER ROLE app_user SET search_path TO app_schema, public;ユーザー単位で継続して適用したい
ALTER DATABASE ... SET対象データベースへの新しい接続ALTER DATABASE mydb SET search_path TO app_schema, public;データベース単位で継続して適用したい

JDBC接続だけ切り替えるならcurrentSchema

JavaやSpring BootなどJDBCを使うアプリケーションだけ参照先を変えたい場合はcurrentSchemaが分かりやすいです。

JDBC設定
jdbc:postgresql://localhost:5432/mydb?currentSchema=app_schema

この設定はJDBC接続を作成するときに検索パスを指定します。PostgreSQL全体やpsqlから作成した別の接続には影響しません。

アプリケーションごとに接続URLを分けられるため、既存SQLを変更せず特定のアプリだけ参照スキーマを切り替えたい場合に向いています。

psqlで一時的に切り替えるならSET search_path

psqlで接続した後一時的に参照スキーマを変更する場合はSET search_pathを実行します。

SQL
SET search_path TO app_schema, public;

この設定はSQLを実行した現在のセッションにだけ適用されます。psqlを終了して接続し直すと通常は元の設定へ戻ります。

設定結果は次のSQLで確認できます。

SQL
SHOW search_path;
SELECT current_schema();

SHOW search_pathでは検索対象となるスキーマの順番、current_schema()では現在最初に参照される有効なスキーマを確認できます。一時的な動作確認や管理作業中だけスキーマを切り替えたい場合はこの方法が手軽ですね。

ユーザー単位で継続するならALTER ROLE

特定のデータベースユーザーが接続したとき、毎回同じ検索パスを使いたい場合はALTER ROLEで設定します。

SQL
ALTER ROLE app_user
SET search_path TO app_schema, public;

設定後app_userが新しく接続するとapp_schemapublicの順でオブジェクトを検索します。

すでに接続中のセッションには反映されないため、設定後に再接続してください。接続プールを使っている場合は既存の接続が残らないようにアプリケーションや接続プールの再起動も必要です。

同じユーザーを複数のアプリケーションで共有している場合、すべてに設定が影響します。特定のアプリケーションだけ切り替えたい場合はALTER ROLEよりcurrentSchemaの方が安全です。

データベース単位で継続するならALTER DATABASE

対象データベースへ接続するユーザーに共通の検索パスを設定したい場合はALTER DATABASEを使います。

SQL
ALTER DATABASE mydb
SET search_path TO app_schema, public;

この設定も新しく作成された接続から適用されます。データベースを利用する複数のユーザーへ影響するため、アプリケーションごとに参照先を分けたい環境には向きません。

アプリとユーザーの設定が重なる場合

ALTER ROLEALTER DATABASEの両方が設定されている環境では、ユーザーとデータベースの組み合わせによって適用される設定が変わることがあります。

運用中の環境では変更前に次のSQLで現在の検索パスを確認してください。

SQL
SHOW search_path;

JDBC接続だけを変更したい場合はcurrentSchema、psqlで一時的に変更したい場合はSET search_path、ユーザーやデータベースの標準設定として残したい場合はALTER ROLEまたはALTER DATABASEと使い分けると分かりやすいです。

複数スキーマを検索パスに含める場合

currentSchemaパラメータはカンマ区切りで複数のスキーマを指定できます。

jdbc.dicon
jdbc:postgresql://localhost:5432/mydb?currentSchema=app_schema,public

この設定ではまずapp_schemaを検索し、見つからなければpublicスキーマを参照します。公式のサンプルデータや拡張機能などをpublicに残しておきたい場合に便利ですね。

注意点とトラブルシューティング

スキーマ名の大文字・小文字について

大文字を含む引用符付きスキーマ名は接続URL上の指定方法やURLエンコードで詰まりやすいため、原則として小文字のスキーマ名を推奨です。既存環境で大文字を使っている場合はSHOW search_pathcurrent_schema()で接続後の値を確認してください。

接続プールを使用している場合

接続プールを利用している環境では設定変更後にアプリケーションサーバーの再起動が必要です。既存の接続が残っていると古い設定が使われ続けることがあるので注意してください。

権限エラーが出る場合

下記のようなエラーが出るケースがあります。

SQL – 実行結果
ERROR: permission denied for schema app_schema

接続ユーザーに対してスキーマのUSAGE権限が付与されているか確認してください。

SQL
GRANT USAGE ON SCHEMA app_schema TO 【DBユーザー名】;

テーブルへのアクセス権限も別途必要です。

SQL
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app_schema TO 【DBユーザー名】;

よくある質問

Spring BootなどのSpringアプリでも同じ方法で使える?

はい、使えます。application.propertiesapplication.ymlのJDBC URL部分に同様にcurrentSchemaを追加するだけです。

application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb?currentSchema=app_schema

currentSchemaとsearch_pathは同じ?

currentSchemaはJDBC接続時にPostgreSQLのsearch_pathを指定するための接続パラメータです。

仕組みは近いですがSET search_pathは現在のセッションでSQLとして実行するのに対し、currentSchemaはJDBC接続URLで指定します。

一時設定、ユーザー単位、データベース単位の違いは「currentSchemaとsearch_pathの違い」で解説しています。

スキーマが存在しない場合はどうなる?

存在しないスキーマはsearch_path上で無視されます。後ろにpublicなど別のスキーマを指定している場合、そちらに同名オブジェクトがあれば参照される可能性があります。
設定後は次のSQLで意図した検索パスになっているか確認してください。SHOW search_path; SELECT current_schema();対象テーブルがどのスキーマにも存在しなければ、SQL実行時にrelation "xxx" does not existが発生します。

currentSchemaは接続後も永続化される?

currentSchemaはそのJDBC接続に適用されます。PostgreSQL全体の設定を書き換えるものではありません。ユーザー単位やデータベース単位で新しい接続へ継続適用したい場合はALTER ROLE ... SET search_pathまたはALTER DATABASE ... SET search_pathを検討します。

PostgreSQLやDocker関連記事はここでまとめて確認!

まとめ

  • JDBC接続文字列にcurrentSchemaパラメータを追加するだけで全SQLでスキーマが自動補完されるよ。
  • スキーマ名を省略していないSQL(ハードコーディングあり)には適用されないので注意だよ。
  • カンマ区切りで複数スキーマの検索パスを設定できるよ。
  • 接続ユーザーへのスキーマUSAGE権限とテーブルアクセス権限を忘れずに付与してね。
  • 接続プール環境では設定変更後にアプリサーバーの再起動が必要だよ。

リプレースや環境移行の作業効率が大幅に上がりますので、ぜひ活用してみてくださいね。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次