JDBCで特定のスキーマに接続する
1. 序章
この記事では、データベーススキーマの基本、それらが必要な理由、およびそれらがどのように役立つかについて説明します。 その後、PostgreSQLをデータベースとしてJDBCでスキーマを設定する実際的な例に焦点を当てます。
2. データベーススキーマとは
一般に、データベーススキーマは、データベースを規制する一連のルールです。 これは、データベースを取り巻く抽象化の追加レイヤーです。 スキーマには次の2種類があります。
- 論理データベーススキーマは、データベースに格納されているデータに適用されるルールを定義します。
- 物理データベーススキーマは、データをストレージシステムに物理的に保存する方法に関するルールを定義します。
PostgreSQLでは、スキーマは第1種を指します。 スキーマは、テーブル、ビュー、インデックスなどのデータベースオブジェクトを含む論理名前空間です。各スキーマは1つのデータベースに属し、各データベースには少なくとも1つのスキーマがあります。 特に指定がない場合。
PostgreSQLのスキーマを使用すると、テーブルとビューをグループに編成し、管理しやすくすることができます。 このようにして、データベースオブジェクトに対する特権をより詳細なレベルで設定できます。 また、スキーマを使用すると、複数のユーザーが干渉することなく同じデータベースを同時に使用できます。
3. PostgreSQLでスキーマを使用する方法
データベーススキーマのオブジェクトにアクセスするには、使用する特定のデータベースオブジェクトの名前の前にスキーマの名前を指定する必要があります。 たとえば、スキーマs tore内のテーブルproduct をクエリするには、テーブルの修飾名を使用する必要があります。
SELECT * FROM store.product;
具体的なスキーマがアプリケーションに結合されないように、スキーマ名をハードコーディングしないことをお勧めします。 これは、データベースオブジェクト名を直接使用し、データベースシステムに使用するスキーマを決定させることを意味します。 PostgreSQLは、検索パスに従って、特定のテーブルを検索する場所を決定します。
3.1. PostgreSQL search_path
検索パスは、特定のデータベースオブジェクトに対するデータベースシステムの検索を定義するスキーマの順序付きリストです。オブジェクトがいずれかの(または複数の)スキーマに存在する場合、最初に検出されたオカレンスを取得します。 そうしないと、エラーが発生します。 検索パスの最初のスキーマは、現在のスキーマとも呼ばれます。 検索パス上にあるスキーマをプレビューするには、次のクエリを使用できます。
SHOW search_path;
デフォルトのPostgreSQL構成は、 $userとパブリックスキーマを返します。 すでに説明したパブリックスキーマ$user スキーマは、現在のユーザーにちなんで名付けられたスキーマであり、存在しない可能性があります。 その場合、データベースはそのスキーマを無視します。
ストアスキーマを検索パスに追加するには、次のクエリを実行します。
SET search_path TO store,public;
この後、スキーマを指定せずに製品テーブルをクエリできます。 また、検索パスからパブリックスキーマを削除することもできます。
上記のように検索パスを設定することは、ROLEレベルでの構成です。 postgresql.conf ファイルを変更し、データベースインスタンスをリロードすることで、データベース全体の検索パスを変更できます。
3.2. JDBC URL
JDBC URLを使用して、接続のセットアップ中にすべての種類のパラメーターを指定できます。 通常のパラメータは、データベースタイプ、アドレス、ポート、データベース名などです。
この概念を実践する前に、テスト環境をセットアップしましょう。 このために、 testcontainers ライブラリを使用して、次のテストセットアップを作成します。
@ClassRule
public static PostgresqlTestContainer container = PostgresqlTestContainer.getInstance();
@BeforeClass
public static void setup() throws Exception {
Properties properties = new Properties();
properties.setProperty("user", container.getUsername());
properties.setProperty("password", container.getPassword());
Connection connection = DriverManager.getConnection(container.getJdbcUrl(), properties);
connection.createStatement().execute("CREATE SCHEMA store");
connection.createStatement().execute("CREATE TABLE store.product(id SERIAL PRIMARY KEY, name VARCHAR(20))");
connection.createStatement().execute("INSERT INTO store.product VALUES(1, 'test product')");
}
@ ClassRule、を使用して、PostgreSQLデータベースコンテナのインスタンスを作成します。 次に、 setup メソッドで、そのデータベースへの接続を作成し、必要なオブジェクトを作成します。
データベースが設定されたら、JDBCURLを使用してstoreスキーマに接続しましょう。
@Test
public void settingUpSchemaUsingJdbcURL() throws Exception {
Properties properties = new Properties();
properties.setProperty("user", container.getUsername());
properties.setProperty("password", container.getPassword());
Connection connection = DriverManager.getConnection(container.getJdbcUrl().concat("&" + "currentSchema=store"), properties);
ResultSet resultSet = connection.createStatement().executeQuery("SELECT * FROM product");
resultSet.next();
assertThat(resultSet.getInt(1), equalTo(1));
assertThat(resultSet.getString(2), equalTo("test product"));
}
デフォルトのスキーマを変更するには、currentSchemaパラメーターを指定する必要があります。存在しないスキーマを入力すると、selectクエリ中にPSQLExceptionがスローされます。データベースオブジェクトがありません。
3.3。PGSimpleDataSource
データベースに接続するには、PGSimpleDataSourceという名前のPostgreSQLドライバーライブラリのjavax.sql.DataSource実装を使用できます。この具体的な実装では、スキーマの設定がサポートされています。
@Test
public void settingUpSchemaUsingPGSimpleDataSource() throws Exception {
int port = //extracting port from container.getJdbcUrl()
PGSimpleDataSource ds = new PGSimpleDataSource();
ds.setServerNames(new String[]{container.getHost()});
ds.setPortNumbers(new int[]{port});
ds.setUser(container.getUsername());
ds.setPassword(container.getPassword());
ds.setDatabaseName("test");
ds.setCurrentSchema("store");
ResultSet resultSet = ds.getConnection().createStatement().executeQuery("SELECT * FROM product");
resultSet.next();
assertThat(resultSet.getInt(1), equalTo(1));
assertThat(resultSet.getString(2), equalTo("test product"));
}
PGSimpleDataSource を使用している間、スキーマを設定しない場合、ドライバーはデフォルトとしてパブリックスキーマを使用します。
3.4. javax.persistenceパッケージからの@Tableアノテーション
プロジェクトでJPAを使用する場合、 @Tableアノテーションを使用して、エンティティレベルでスキーマを指定できます。 この注釈は、スキーマの値を保持するか、デフォルトで空にすることができます。
@Entity
@Table(name = "product", schema = "store")
public class Product {
@Id
private int id;
private String name;
// getters and setters
}
この動作を確認するために、 EntityManager インスタンスを設定して、productテーブルをクエリします。
@Test
public void settingUpSchemaUsingTableAnnotation(){
Map<String,String> props = new HashMap<>();
props.put("hibernate.connection.url", container.getJdbcUrl());
props.put("hibernate.connection.user", container.getUsername());
props.put("hibernate.connection.password", container.getPassword());
EntityManagerFactory emf = Persistence.createEntityManagerFactory("postgresql_schema_unit", props);
EntityManager entityManager = emf.createEntityManager();
Product product = entityManager.find(Product.class, 1);
assertThat(product.getName(), equalTo("test product"));
}
セクション3で前述したように、さまざまな理由から、スキーマをコードに結合することは避けるのが最善です。 そのため、この機能は見過ごされがちですが、複数のスキーマにアクセスする場合に有利な場合があります。
4. 結論
このチュートリアルでは、最初に、データベーススキーマに関する基本的な理論について説明しました。 その後、さまざまなアプローチとテクノロジーを使用してデータベーススキーマを設定する複数の方法について説明しました。 いつものように、すべてのコードサンプルはGitHubで利用できます。