1. 序章

この記事では、データベーススキーマの基本、それらが必要な理由、およびそれらがどのように役立つかについて説明します。 その後、PostgreSQLをデータベースとしてJDBCでスキーマを設定する実際的な例に焦点を当てます。

2. データベーススキーマとは

一般に、データベーススキーマは、データベースを規制する一連のルールです。 これは、データベースを取り巻く抽象化の追加レイヤーです。 スキーマには次の2種類があります。

  1. 論理データベーススキーマは、データベースに格納されているデータに適用されるルールを定義します。
  2. 物理データベーススキーマは、データをストレージシステムに物理的に保存する方法に関するルールを定義します。

PostgreSQLでは、スキーマは第1種を指します。 スキーマは、テーブル、ビュー、インデックスなどのデータベースオブジェクトを含む論理名前空間です。各スキーマは1つのデータベースに属し、各データベースには少なくとも1つのスキーマがあります。 特に指定がない場合。 PostgreSQLのデフォルトのスキーマはパブリックです。 スキーマを指定せずに作成するすべてのデータベースオブジェクトは、 公衆スキーマ。

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を使用して、接続のセットアップ中にすべての種類のパラメーターを指定できます。 通常のパラメータは、データベースタイプ、アドレス、ポート、データベース名などです。 Postgresバージョン9.4以降。 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利用できます。