6.10. SQL 缓存存储


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

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

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

SQL 表和查询存储:

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

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

注意

SQL 缓存存储不支持过期或分段。

6.10.1. 密钥和值的数据类型

数据网格通过 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 列作为键,标题 列作为值。

6.10.1.1. 复合键和值

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

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

提示

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

复合值

下表包含 标题和 作者 列的复合值:

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

对于键和值,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 type

int4

int32

int8

int64

float4

浮点值

float8

double

numeric

double

bool

bool

char

字符串

varchar

字符串

文本,tinytext,mediumtext,longtext

字符串

bytea,tinyblob,blob,mediumblob,longblob

bytes

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

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

先决条件

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

    提示

    数据网格建议使用 Protobuf 处理器生成 Protobuf 模式。对于远程缓存,您可以通过数据网格控制台、CLI 或 REST API 来添加模式来注册模式。

流程

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

    • 远程缓存:将数据库驱动程序复制到 Data Grid 服务器安装的 server/lib 目录中。
    • 嵌入式缓存:在您的 pom 文件中添加 infinispan-cachestore-sql 依赖项。

      <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:13.0"
    Copy to Clipboard Toggle word wrap

    programmatic

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

  4. 使用 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 ("<database_table_name>")来加载缓存的 数据库表。
  7. 添加 schema 元素或 .schemaJdbcConfigurationBuilder () 方法,并为复合键或值添加 Protobuf 模式配置。

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

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

XML

<distributed-cache>
  <persistence>
    <table-jdbc-store xmlns="urn:infinispan:config:store:sql:13.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 注册您的模式。

    提示

    数据网格建议使用 Protobuf 处理器生成 Protobuf 模式。对于远程缓存,您可以通过数据网格控制台、CLI 或 REST API 来添加模式来注册模式。

流程

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

    • 远程缓存:将数据库驱动程序复制到 Data Grid 服务器安装的 server/lib 目录中。
    • 嵌入式缓存:将 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 查询缓存存储。

    声明性

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

    programmatic

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

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

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

    Expand
    query 语句描述

    选择

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

    选择所有

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

    SIZE

    计算缓存中条目的数量。

    DELETE

    从缓存中删除单个条目。

    全部删除

    从缓存中删除所有条目。

    UPSERT

    修改缓存中的条目。

    注意

    DELETE、DELEALLUPSERT 语句不适用于只读缓存存储,但如果缓存存储允许修改,则需要使用。

    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 包含值 in values 中的键,则为 嵌入式-key 属性或嵌入式Key () 方法设置值 true
  8. 保存对您的配置的更改。

6.10.3.1. SQL 查询存储配置

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

SQL 语句

用于"个人"和"地址"表的 SQL 数据定义语言(DDL)语句如下:

"人"表的 SQL 语句

CREATE TABLE Person (
  name VARCHAR(255) NOT NULL,
  picture VARBINARY(255),
  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 schema

protobuf 用于 "person" 和 "address" 表的 schema,如下所示:

protobuf schema for the "person" 表

package com.example

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

protobuf schema for the "address" 表

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

缓存配置

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

XML

<distributed-cache>
  <persistence>
    <query-jdbc-store xmlns="urn:infinispan:config:store:jdbc:13.0"
                      dialect="POSTGRES"
                      shared="true">
      <queries key-columns="name">
        <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 = t2.name WHERE t1.name = :name</select-single>
        <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</select-all>
        <delete-single>DELETE FROM Person t1 WHERE t1.name = :name; DELETE FROM Address t2 where t2.name = :name</delete-single>
        <delete-all>DELETE FROM Person; DELETE FROM Address</delete-all>
        <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)</upsert>
        <size>SELECT COUNT(*) FROM Person</size>
      </queries>
      <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",
        "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 = t2.name WHERE t1.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"
      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 = t2.name WHERE t1.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 = t2.name WHERE t1.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

数据网格在以下情况下记录这个信息:

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

要解决这个问题,应该:

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

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

Theme

© 2025 Red Hat