6.10. SQL 缓存存储


SQL 缓存存储可让您从现有数据库表加载 Data Grid 缓存。Data Grid 提供两种类型的 SQL 缓存存储:

Data Grid 从单个数据库表中加载条目。
查询
Data Grid 使用 SQL 查询来加载来自单个或多个数据库表的条目,包括这些表中的子列,以及执行插入、更新和删除操作。
提示

访问代码教程,以尝试操作中的 SQL 缓存存储。请参阅适用于 远程缓存的 Persistence 代码教程

SQL 表和查询存储:

  • 允许对持久性存储的读取和写入操作。
  • 可以是只读的,作为缓存加载程序。
  • 支持与单个数据库列或多个数据库列复合对应的键和值。

    对于复合键和值,您必须为 Data Grid 提供用于描述键和值的 Protobuf 模式(.proto 文件)。借助 Data Grid 服务器,您可以使用 schema 命令通过 Data Grid Console 或命令行界面(CLI)添加 模式

警告

SQL 缓存存储用于现有数据库表。因此,它不会存储任何元数据,包括过期、片段和版本元数据。由于没有版本存储,SQL 存储不支持最佳事务缓存和异步跨站点复制。这个限制还扩展至 Hot Rod 版本的操作。

提示

当 SQL 缓存存储配置为只读时,它与 SQL 缓存存储一起使用过期。expiration 从内存中删除过时的值,从而导致缓存再次从数据库中获取值并将其缓存。

6.10.1. 键和值的数据类型

Data Grid 通过 SQL 缓存存储从数据库表中的列加载键和值,自动使用适当的数据类型。以下 CREATE 语句添加名为"books"的表,它有两个列,即 isbntitle

带有两列的数据库表

CREATE TABLE books (
    isbn NUMBER(13),
    title varchar(120)
    PRIMARY KEY(isbn)
);
Copy to Clipboard Toggle word wrap

当您将此表与 SQL 缓存存储搭配使用时,Data Grid 会使用 isbn 列作为键,将 title 列作为值添加到缓存中。

6.10.1.1. 复合键和值

您可以将 SQL 存储与包含复合主键或复合值的数据库表一起使用。

要使用复合键或值,您必须为 Data Grid 提供用于描述数据类型的 Protobuf 模式。您还必须在 SQL 存储中添加 schema 配置,并为键和值指定消息名称。

提示

Data Grid 建议使用 ProtoStream 处理器生成 Protobuf 模式。然后,您可以通过 Data Grid Console、CLI 或 REST API 上传远程缓存的 Protobuf 模式。

复合值

以下数据库表包含 titleauthor 列的复合值:

CREATE TABLE books (
    isbn NUMBER(13),
    title varchar(120),
    author varchar(80)
    PRIMARY KEY(isbn)
);
Copy to Clipboard Toggle word wrap

Data Grid 使用 isbn 列作为密钥在缓存中添加一个条目。对于该值,Data Grid 需要 Protobuf 模式来映射 title 列和 作者 列:

package library;

message books_value {
    optional string title = 1;
    optional string author = 2;
}
Copy to Clipboard Toggle word wrap
复合键和值

以下数据库表包含一个复合主键和一个组合值,各自有两个列:

CREATE TABLE books (
    isbn NUMBER(13),
    reprint INT,
    title varchar(120),
    author varchar(80)
    PRIMARY KEY(isbn, reprint)
);
Copy to Clipboard Toggle word wrap

对于 key 和 value,Data Grid 需要 Protobuf 模式,它将列映射到键和值:

package library;

message books_key {
    required string isbn = 1;
    required int32 reprint = 2;
}

message books_value {
    optional string title = 1;
    optional string author = 2;
}
Copy to Clipboard Toggle word wrap

6.10.1.2. 嵌入式密钥

protobuf 模式可在值中包含键,如下例所示:

带有嵌入式密钥的 protobuf 模式

package library;

message books_key {
    required string isbn = 1;
    required int32 reprint = 2;
}

message books_value {
    required string isbn = 1;
    required string reprint = 2;
    optional string title = 3;
    optional string author = 4;
}
Copy to Clipboard Toggle word wrap

要使用嵌入的密钥,您必须在 SQL 存储配置中包含 embedded-key="true" 属性或 embeddedKey (true) 方法。

6.10.1.3. SQL 类型到 Protobuf 类型

下表包含 SQL 数据类型的默认映射到 Protobuf 数据类型:

Expand
SQL 类型protobuf 类型

int4

int32

int8

int64

FLOAT4

浮点值

float8

double

数字

double

bool

bool

char

string

varchar

string

文本,tinytext,mediumtext,longtext

string

bytea,tinyblob,blob,mediumblob,longblob

bytes

6.10.2. 从数据库表加载 Data Grid 缓存

如果您希望 Data Grid 从数据库表载入数据,请将 SQL 表缓存存储到配置中。当它连接到数据库时,Data Grid 使用表中的元数据来检测列名称和数据类型。Data Grid 还自动决定数据库中哪些列是主密钥的一部分。

先决条件

  • 具有 JDBC 连接详细信息。
    您可以在缓存配置中直接添加 JDBC 连接工厂。
    对于生产环境中的远程缓存,您应该将受管数据源添加到 Data Grid Server 配置中,并在缓存配置中指定 JNDI 名称。
  • 为任何复合键或复合值生成 Protobuf 模式,并将您的架构注册到 Data Grid。

    提示

    Data Grid 建议使用 ProtoStream 处理器生成 Protobuf 模式。对于远程缓存,您可以通过 Data Grid Console、CLI 或 REST API 添加架构来注册您的模式。

流程

  1. 在您的 Data Grid 部署中添加数据库驱动程序。

    • 远程缓存:将数据库驱动程序复制到 Data Grid Server 安装中的 server/lib 目录。

      提示

      使用带有 Data Grid 命令行界面(CLI)的 install 命令,将所需的驱动程序下载到 server/lib 目录中,例如:

      install org.postgresql:postgresql:42.4.3
      Copy to Clipboard Toggle word wrap
    • 嵌入式缓存:将 infinispan-cachestore-sql 依赖项添加到 pom 文件中。

      <dependency>
        <groupId>org.infinispan</groupId>
        <artifactId>infinispan-cachestore-sql</artifactId>
      </dependency>
      Copy to Clipboard Toggle word wrap
  2. 打开 Data Grid 配置以进行编辑。
  3. 添加 SQL 表缓存存储。

    声明

    table-jdbc-store xmlns="urn:infinispan:config:store:sql:15.0"
    Copy to Clipboard Toggle word wrap

    programmatic

    persistence().addStore(TableJdbcStoreConfigurationBuilder.class)
    Copy to Clipboard Toggle word wrap

  4. 使用 dialect="" 或 dialect ()指定数据库 dialect (),如 dialect="H2"dialect="postgres "。
  5. 使用您需要的属性配置 SQL 缓存存储,例如:

    • 要在集群中使用相同的缓存存储,请设置 shared="true"shared (true)
    • 要创建只读缓存存储,请设置 read-only="true".ignoreModifications (true)
  6. 使用 table -name="<database_table_name>" 或 table .name ("& lt;database_table_name>") 加载缓存的数据库表。
  7. 添加 schema 元素或 .schemaJdbcConfigurationBuilder () 方法,并为复合键或值添加 Protobuf 模式配置。

    1. 使用 package 属性或 package () 方法指定软件包名称。
    2. 使用 message-name 属性或 messageName () 方法指定复合值。
    3. 使用 key-message-name 属性或 keyMessageName () 方法指定复合键。
    4. 如果您的 schema 在值中包含键,请为 embedded-key 属性或 embeddedKey () 方法设置 true 值。
  8. 保存对配置的更改。
SQL 表存储配置

以下示例使用 Protobuf 模式中定义的复合值从名为"books"的数据库表加载分布式缓存:

XML

<distributed-cache>
  <persistence>
    <table-jdbc-store xmlns="urn:infinispan:config:store:sql:15.0"
                      dialect="H2"
                      shared="true"
                      table-name="books">
      <schema message-name="books_value"
              package="library"/>
    </table-jdbc-store>
  </persistence>
</distributed-cache>
Copy to Clipboard Toggle word wrap

JSON

{
  "distributed-cache": {
    "persistence": {
      "table-jdbc-store": {
        "dialect": "H2",
        "shared": "true",
        "table-name": "books",
        "schema": {
          "message-name": "books_value",
          "package": "library"
        }
      }
    }
  }
}
Copy to Clipboard Toggle word wrap

YAML

distributedCache:
  persistence:
    tableJdbcStore:
      dialect: "H2"
      shared: "true"
      tableName: "books"
      schema:
        messageName: "books_value"
        package: "library"
Copy to Clipboard Toggle word wrap

ConfigurationBuilder

ConfigurationBuilder builder = new ConfigurationBuilder();
builder.persistence().addStore(TableJdbcStoreConfigurationBuilder.class)
      .dialect(DatabaseType.H2)
      .shared("true")
      .tableName("books")
      .schemaJdbcConfigurationBuilder()
        .messageName("books_value")
        .packageName("library");
Copy to Clipboard Toggle word wrap

6.10.3. 使用 SQL 查询来加载数据并执行操作

SQL 查询缓存存储可让您从多个数据库表加载缓存,包括从数据库表中的子列加载缓存,以及执行插入、更新和删除操作。

先决条件

  • 具有 JDBC 连接详细信息。
    您可以在缓存配置中直接添加 JDBC 连接工厂。
    对于生产环境中的远程缓存,您应该将受管数据源添加到 Data Grid Server 配置中,并在缓存配置中指定 JNDI 名称。
  • 为任何复合键或复合值生成 Protobuf 模式,并将您的架构注册到 Data Grid。

    提示

    Data Grid 建议使用 ProtoStream 处理器生成 Protobuf 模式。对于远程缓存,您可以通过 Data Grid Console、CLI 或 REST API 添加架构来注册您的模式。

流程

  1. 在您的 Data Grid 部署中添加数据库驱动程序。

    • 远程缓存:将数据库驱动程序复制到 Data Grid Server 安装中的 server/lib 目录。

      提示

      使用带有 Data Grid 命令行界面(CLI)的 install 命令,将所需的驱动程序下载到 server/lib 目录中,例如:

      install org.postgresql:postgresql:42.4.3
      Copy to Clipboard Toggle word wrap
    • 嵌入式缓存:将 infinispan-cachestore-sql 依赖项添加到 pom 文件中,并确保数据库驱动程序位于应用程序 classpath 中。

      <dependency>
        <groupId>org.infinispan</groupId>
        <artifactId>infinispan-cachestore-sql</artifactId>
      </dependency>
      Copy to Clipboard Toggle word wrap
  2. 打开 Data Grid 配置以进行编辑。
  3. 添加 SQL 查询缓存存储。

    声明

    query-jdbc-store xmlns="urn:infinispan:config:store:sql:15.0"
    Copy to Clipboard Toggle word wrap

    programmatic

    persistence().addStore(QueriesJdbcStoreConfigurationBuilder.class)
    Copy to Clipboard Toggle word wrap

  4. 使用 dialect="" 或 dialect ()指定数据库 dialect (),如 dialect="H2"dialect="postgres "。
  5. 使用您需要的属性配置 SQL 缓存存储,例如:

    • 要在集群中使用相同的缓存存储,请设置 shared="true"shared (true)
    • 要创建只读缓存存储,请设置 read-only="true".ignoreModifications (true)
  6. 定义 SQL 查询语句,以使用 queries 元素或 queries () 方法加载缓存并修改数据库表。

    Expand
    query 语句描述

    选择

    将单个条目加载到缓存中。您可以使用通配符,但必须为密钥指定参数。您可以使用标记的表达式。

    选择所有

    将多个条目加载到缓存中。如果返回的列数与 key 和 value 列匹配,您可以使用 * 通配符。您可以使用标记的表达式。

    SIZE

    计算缓存中的条目数。

    DELETE

    从缓存中删除单个条目。

    全部删除

    从缓存中删除所有条目。

    UPSERT

    修改缓存中的条目。

    注意

    DELETEDELETE ALLUPSERT 语句不适用于只读缓存存储,但当缓存存储允许修改时是必需的。

    DELETE 语句中的参数必须完全匹配 SELECT 语句中的参数。

    UPSERT 语句中的变量必须具有与 SELECTSELECT ALL 语句返回相同的唯一命名变量。例如,如果 SELECT 返回 foobar this 语句必须只使用 :foo:bar 作为变量。但是,您可以在 语句中应用相同的命名变量。

    SQL 查询可以包含 JOINON 以及数据库支持的任何其他子句。

  7. 添加 schema 元素或 .schemaJdbcConfigurationBuilder () 方法,并为复合键或值添加 Protobuf 模式配置。

    1. 使用 package 属性或 package () 方法指定软件包名称。
    2. 使用 message-name 属性或 messageName () 方法指定复合值。
    3. 使用 key-message-name 属性或 keyMessageName () 方法指定复合键。
    4. 如果您的 schema 在值中包含键,请为 embedded-key 属性或 embeddedKey () 方法设置 true 值。
  8. 保存对配置的更改。

6.10.3.1. SQL 查询存储配置

本节为 SQL 查询缓存存储提供了一个示例配置,它加载带有两个数据库表的数据的分布式缓存:"person" 和 "address"。

SQL 语句

以下示例演示了"person"和"address"表的 SQL 数据定义语言(DDL)语句。示例中描述的数据类型仅适用于 PostgreSQL 数据库。

"person" 表的 SQL 语句

CREATE TABLE Person (
  name VARCHAR(255) NOT NULL,
  picture BYTEA,
  sex VARCHAR(255),
  birthdate TIMESTAMP,
  accepted_tos BOOLEAN,
  notused VARCHAR(255),
  PRIMARY KEY (name)
);
Copy to Clipboard Toggle word wrap

"address" 表的 SQL 语句

CREATE TABLE Address (
  name VARCHAR(255) NOT NULL,
  street VARCHAR(255),
  city VARCHAR(255),
  zip INT,
  PRIMARY KEY (name)
);
Copy to Clipboard Toggle word wrap

protobuf 模式

"person"和"address"表的 protobuf 模式如下:

"address" 表的 protobuf 模式

package com.example;

message Address {
   optional string street = 1;
   optional string city = 2 [default = "San Jose"];
   optional int32 zip = 3 [default = 0];
}
Copy to Clipboard Toggle word wrap

"person" 表的 protobuf 模式

package com.example;

import "/path/to/address.proto";

enum Sex {
   FEMALE = 1;
   MALE = 2;
}

message Person {
   optional string name = 1;
   optional Address address = 2;
   optional bytes picture = 3;
   optional Sex sex = 4;
   optional fixed64 birthDate = 5 [default = 0];
   optional bool accepted_tos = 6 [default = false];
}
Copy to Clipboard Toggle word wrap

缓存配置

以下示例使用包含 JOIN 子句的 SQL 查询从"person"和"地址"表中加载分布式缓存:

XML

<distributed-cache>
  <persistence>
    <query-jdbc-store xmlns="urn:infinispan:config:store:sql:15.0"
                      dialect="POSTGRES"
                      shared="true" key-columns="name">
          <connection-pool driver="org.postgresql.Driver"
                            connection-url="jdbc:postgresql://localhost:5432/postgres"
                            username="postgres"
                            password="changeme"/>
      <queries select-single="SELECT t1.name, t1.picture, t1.sex, t1.birthdate, t1.accepted_tos, t2.street, t2.city, t2.zip FROM Person t1 JOIN Address t2 ON t1.name = :name AND t2.name = :name"
        select-all="SELECT t1.name, t1.picture, t1.sex, t1.birthdate, t1.accepted_tos, t2.street, t2.city, t2.zip FROM Person t1 JOIN Address t2 ON t1.name = t2.name"
        delete-single="DELETE FROM Person t1 WHERE t1.name = :name; DELETE FROM Address t2 where t2.name = :name"
        delete-all="DELETE FROM Person; DELETE FROM Address"
        upsert="INSERT INTO Person (name,  picture, sex, birthdate, accepted_tos) VALUES (:name, :picture, :sex, :birthdate, :accepted_tos); INSERT INTO Address(name, street, city, zip) VALUES (:name, :street, :city, :zip)"
        size="SELECT COUNT(*) FROM Person"
      />
      <schema message-name="Person"
              package="com.example"
              embedded-key="true"/>
    </query-jdbc-store>
  </persistence>
</distributed-cache>
Copy to Clipboard Toggle word wrap

JSON

{
  "distributed-cache": {
    "persistence": {
      "query-jdbc-store": {
        "dialect": "POSTGRES",
        "shared": "true",
        "key-columns": "name",
        "connection-pool": {
          "username": "postgres",
          "password": "changeme",
          "driver": "org.postgresql.Driver",
          "connection-url": "jdbc:postgresql://localhost:5432/postgres"
        },
        "queries": {
          "select-single": "SELECT t1.name, t1.picture, t1.sex, t1.birthdate, t1.accepted_tos, t2.street, t2.city, t2.zip FROM Person t1 JOIN Address t2 ON t1.name = :name AND t2.name = :name",
          "select-all": "SELECT t1.name, t1.picture, t1.sex, t1.birthdate, t1.accepted_tos, t2.street, t2.city, t2.zip FROM Person t1 JOIN Address t2 ON t1.name = t2.name",
          "delete-single": "DELETE FROM Person t1 WHERE t1.name = :name; DELETE FROM Address t2 where t2.name = :name",
          "delete-all": "DELETE FROM Person; DELETE FROM Address",
          "upsert": "INSERT INTO Person (name,  picture, sex, birthdate, accepted_tos) VALUES (:name, :picture, :sex, :birthdate, :accepted_tos); INSERT INTO Address(name, street, city, zip) VALUES (:name, :street, :city, :zip)",
          "size": "SELECT COUNT(*) FROM Person"
        },
        "schema": {
          "message-name": "Person",
          "package": "com.example",
          "embedded-key": "true"
        }
      }
    }
  }
}
Copy to Clipboard Toggle word wrap

YAML

distributedCache:
  persistence:
    queryJdbcStore:
      dialect: "POSTGRES"
      shared: "true"
      keyColumns: "name"
      connectionPool:
        username: "postgres"
        password: "changeme"
        driver: "org.postgresql.Driver"
        connectionUrl: "jdbc:postgresql://localhost:5432/postgres"
      queries:
        selectSingle: "SELECT t1.name, t1.picture, t1.sex, t1.birthdate, t1.accepted_tos, t2.street, t2.city, t2.zip FROM Person t1 JOIN Address t2 ON t1.name = :name AND t2.name = :name"
        selectAll: "SELECT t1.name, t1.picture, t1.sex, t1.birthdate, t1.accepted_tos, t2.street, t2.city, t2.zip FROM Person t1 JOIN Address t2 ON t1.name = t2.name"
        deleteSingle: "DELETE FROM Person t1 WHERE t1.name = :name; DELETE FROM Address t2 where t2.name = :name"
        deleteAll: "DELETE FROM Person; DELETE FROM Address"
        upsert: "INSERT INTO Person (name,  picture, sex, birthdate, accepted_tos) VALUES (:name, :picture, :sex, :birthdate, :accepted_tos); INSERT INTO Address(name, street, city, zip) VALUES (:name, :street, :city, :zip)"
        size: "SELECT COUNT(*) FROM Person"
      schema:
        messageName: "Person"
        package: "com.example"
        embeddedKey: "true"
Copy to Clipboard Toggle word wrap

ConfigurationBuilder

ConfigurationBuilder builder = new ConfigurationBuilder();
builder.persistence().addStore(QueriesJdbcStoreConfigurationBuilder.class)
      .dialect(DatabaseType.POSTGRES)
      .shared("true")
      .keyColumns("name")
      .queriesJdbcConfigurationBuilder()
         .select("SELECT t1.name, t1.picture, t1.sex, t1.birthdate, t1.accepted_tos, t2.street, t2.city, t2.zip FROM Person t1 JOIN Address t2 ON t1.name = :name AND t2.name = :name")
         .selectAll("SELECT t1.name, t1.picture, t1.sex, t1.birthdate, t1.accepted_tos, t2.street, t2.city, t2.zip FROM Person t1 JOIN Address t2 ON t1.name = t2.name")
         .delete("DELETE FROM Person t1 WHERE t1.name = :name; DELETE FROM Address t2 where t2.name = :name")
         .deleteAll("DELETE FROM Person; DELETE FROM Address")
         .upsert("INSERT INTO Person (name,  picture, sex, birthdate, accepted_tos) VALUES (:name, :picture, :sex, :birthdate, :accepted_tos); INSERT INTO Address(name, street, city, zip) VALUES (:name, :street, :city, :zip)")
         .size("SELECT COUNT(*) FROM Person")
      .schemaJdbcConfigurationBuilder()
         .messageName("Person")
         .packageName("com.example")
         .embeddedKey(true);
Copy to Clipboard Toggle word wrap

6.10.4. SQL 缓存存储故障排除

查找有关 SQL 缓存存储的常见问题和错误以及如何对它们进行故障排除。

ISPN008064: No primary keys found for table <table_name>, check case sensitivity
Copy to Clipboard Toggle word wrap

在以下情况下,Data Grid 会记录此消息:

  • 数据库表不存在。
  • 数据库表名称区分大小写,需要都是小写或所有大写,具体取决于数据库提供程序。
  • 数据库表没有定义任何主键。

要解决这个问题,您应该:

  1. 检查 SQL 缓存存储配置,并确保指定了现有表的名称。
  2. 确保数据库表名称符合问题单敏感度要求。
  3. 确保您的数据库表具有唯一标识适当行的主要键。
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat