Skip to content

Table API

要操作某个表,需要获取该表的特定视图并调用其方法,只能使用 SQL API 创建表。

Ignite 支持将用户对象映射到表元组,这使得用任何编程语言创建的对象都可以直接用于键-值操作。

1.Ignite中的表视图

1.1.元组和键-值视图

在处理表时,Ignite提供了两种方法:直接处理数据或将数据映射到类。直接数据处理方法处理数据元组。或者,在将数据映射到类时,数据会根据数据库交互的需要在这些类之间进行转换。

1.2.记录和键-值视图

创建视图时可以创建RecordViewKeyValueView,这些视图类型之间的主要区别在于使用的 API。

RecordView 中,会创建一个记录,其中包含这一行数据的所有信息,包含所有字段,也包括主键。

KeyValueView 中,可以使用键-值映射。可以将其视为一个字典,其中键对象包含一个或多个主键字段,值对象包含数据字段。当主键与业务对象没有直接关系时,可能不希望将主键加入业务对象,此方法非常有用。

2.数据类型支持

2.1.时间和日期数据类型

表视图只支持 JavaTime API,以下数据类型是不支持的:

  • java.util.Date
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp

请使用如下的数据类型:

  • java.time.LocalDate
  • java.time.LocalTime
  • java.time.LocalDateTime
  • java.time.Instant

3.获取Table实例

使用IgniteTables.table(String)方法可以获取表的实例,还可以使用IgniteTables.tables()方法列出所有现有表。

java
IgniteTables tableApi = client.tables();
List<Table> existingTables = tableApi.tables();
Table firstTable = existingTables.get(0);
csharp
var existingTables = await Client.Tables.GetTablesAsync();
var firstTable = existingTables[0];

var myTable = await Client.Tables.GetTableAsync("MY_TABLE");
cpp
using namespace ignite;

auto table_api = client.get_tables();
std::vector<table> existing_tables = table_api.get_tables();
table first_table = existing_tables.front();

std::optional<table> my_table = table_api.get_table("MY_TABLE");

如果未指定模式名,则默认会使用PUBLIC模式。如果指定则从指定的模式中获取表。

3.1.限定表名对象

除了使用一个字符串来指定表名,还可以创建一个QualifiedName对象来持有一个全限定表名,Ignite 提供了两种方法来创建限定表名:

  • 使用parse方法来解析全限定表名:
    java
    QualifiedName qualifiedTableName = QualifiedName.parse("PUBLIC.Person");
    Table myTable = tableApi.table(qualifiedTableName);
  • 可以使用of方法来单独指定模式名和表名:
    java
    QualifiedName qualifiedTableName = QualifiedName.of("PUBLIC", "MY_TABLE");
    Table myTable = tableApi.table(qualifiedTableName);

这里的名称必须遵循标识符的SQL语法规则:

  • 标识符必须以LuL1LtLmLoNl Unicode类别中的字符或 U+0331(下划线)开头;
  • 标识符字符(第一个除外)可以是 U+00B7(中点),也可以是 MnMcNdPcCf Unicode类别中的任何字符;
  • 包含任何其他字符的标识符必须用 U+2033(双引号)括起来;
  • 标识符内的双引号必须用2个双引号字符转义。

任何未被引用的名字都将被转换为大写,这时,PersonPERSON名称是等价的,否则就需在名称周围添加转义引号。例如,\"Person\"将被编码为区分大小写的Person名称。如果名称中包含U+2033(双引号)符号,则必须转义为""(2个双引号符号)。

例如:

java
// Case-insensitive table `MY_TABLE` in a case-insensitive `PUBLIC` schema.
QualifiedName.parse("public.my_table"))

// Case-sensitive table `my_table` in a case-sensitive `public` schema.
QualifiedName.parse("\"public\".\"my_table\""))

// Same as above, but with comma as separator that needs to be surrounded by quote characters.
QualifiedName.of("\"public\"","\"my_table\""))

// Case-sensitive name my"table.
QualifiedName.parse("\"my\"\"table\""));

// Case-sensitive table name `public.my_table` in a default schema.
QualifiedName.parse("\"public.my_table\""));

4.Table的基本操作

拿到Table实例后,就需要选择一个视图来确定如何操作数据。

4.1.元组记录视图

该视图可用于直接操作表元组。从元组视图中检索数据时,可以使用多种方法来检索存储在元组中的特定类型的数据。

java
RecordView<Tuple> accounts = client.tables().table("accounts").recordView();

System.out.println("\nInserting a record into the 'accounts' table...");

Tuple newAccountTuple = Tuple.create()
        .set("accountNumber", 123456)
        .set("firstName", "Val")
        .set("lastName", "Kulichenko")
        .set("balance", 100.00d);

accounts.insert(null, newAccountTuple);

System.out.println("\nRetrieving a record using RecordView API...");

Tuple accountNumberTuple = Tuple.create().set("accountNumber", 123456);

Tuple accountTuple = accounts.get(null, accountNumberTuple);

System.out.println(
        "\nRetrieved record:\n"
                + "    Account Number: " + accountTuple.intValue("accountNumber") + '\n'
                + "    Owner: " + accountTuple.stringValue("firstName") + " " + accountTuple.stringValue("lastName") + '\n'
                + "    Balance: $" + accountTuple.doubleValue("balance"));
csharp
IRecordView<IIgniteTuple> view = table.RecordBinaryView;

IIgniteTuple fullRecord = new IgniteTuple
{
  ["id"] = 42,
  ["name"] = "John Doe"
};

await view.UpsertAsync(transaction: null, fullRecord);

IIgniteTuple keyRecord = new IgniteTuple { ["id"] = 42 };
(IIgniteTuple value, bool hasValue) = await view.GetAsync(transaction: null, keyRecord);

Debug.Assert(hasValue);
Debug.Assert(value.FieldCount == 2);
Debug.Assert(value["id"] as int? == 42);
Debug.Assert(value["name"] as string == "John Doe");
cpp
record_view<ignite_tuple> view = table.get_record_binary_view();

ignite_tuple record{
  {"id", 42},
  {"name", "John Doe"}
};

view.upsert(nullptr, record);
std::optional<ignite_tuple> res_record = view.get(nullptr, {"id", 42});

assert(res_record.has_value());
assert(res_record->column_count() == 2);
assert(res_record->get<std::int64_t>("id") == 42);
assert(res_record->get<std::string>("name") == "John Doe");

4.2.记录视图

该视图映射到一个自定义类型上,可以使用映射到表元组的用户对象来操作表。

创建类型转换器:

java
static class CityIdConverter implements TypeConverter<String, Integer> {

    @Override
    public String  toObjectType(Integer columnValue) {
        return columnValue.toString();
    }

    @Override
    public Integer toColumnType(String cityId) {
        return Integer.parseInt(cityId);
    }
}

然后构建转换器并获得RecordView:

java
public static void main(String[] args) throws Exception {
    var mapper = Mapper.builder(Person.class)
            .automap()
            .map("cityId", "city_id", new CityIdConverter())
            .build();

    try (IgniteClient client = IgniteClient.builder()
            .addresses("127.0.0.1:10800")
            .build()
    ) {
        RecordView<Person> view = client.tables()
                .table("person")
                .recordView(mapper);


        Person myPerson = new Person(2, "2", "John Doe", 40, "Apache");

        view.upsert(null, myPerson);
    }
}

对映射到表元组的自定义类型执行表操作:

java
RecordView<Account> accounts = client.tables()
        .table("accounts")
        .recordView(Account.class);

System.out.println("\nInserting a record into the 'accounts' table...");

Account newAccount = new Account(
        123456,
        "Val",
        "Kulichenko",
        100.00d
);

accounts.insert(null, newAccount);

System.out.println("\nRetrieving a record using RecordView API...");

Account account = accounts.get(null, new Account(123456));

System.out.println(
        "\nRetrieved record:\n"
            + "    Account Number: " + account.accountNumber + '\n'
            + "    Owner: " + account.firstName + " " + account.lastName + '\n'
            + "    Balance: $" + account.balance);
csharp
var pocoView = table.GetRecordView<Poco>();

await pocoView.UpsertAsync(transaction: null, new Poco(42, "John Doe"));
var (value, hasValue) = await pocoView.GetAsync(transaction: null, new Poco(42));

Debug.Assert(hasValue);
Debug.Assert(value.Name == "John Doe");

public record Poco(long Id, string? Name = null);
cpp
record_view<person> view = table.get_record_view<person>();

person record(42, "John Doe");

view.upsert(nullptr, record);
std::optional<person> res_record = view.get(nullptr, person{42});

assert(res.has_value());
assert(res->id == 42);
assert(res->name == "John Doe");

4.3.元组键-值视图

该视图可以分别使用键和值元组来操作表。从元组视图检索数据时,可以使用各种方法来检索存储在元组中的特定类型的数据。

java
KeyValueView<Tuple, Tuple> kvView = client.tables().table("accounts").keyValueView();

System.out.println("\nInserting a key-value pair into the 'accounts' table...");

Tuple key = Tuple.create()
        .set("accountNumber", 123456);

Tuple value = Tuple.create()
        .set("firstName", "Val")
        .set("lastName", "Kulichenko")
        .set("balance", 100.00d);

kvView.put(null, key, value);

System.out.println("\nRetrieving a value using KeyValueView API...");

value = kvView.get(null, key);

System.out.println(
        "\nRetrieved value:\n"
                + "    Account Number: " + key.intValue("accountNumber") + '\n'
                + "    Owner: " + value.stringValue("firstName") + " " + value.stringValue("lastName") + '\n'
                + "    Balance: $" + value.doubleValue("balance"));
csharp
IKeyValueView<IIgniteTuple, IIgniteTuple> kvView = table.KeyValueBinaryView;

IIgniteTuple key = new IgniteTuple { ["id"] = 42 };
IIgniteTuple val = new IgniteTuple { ["name"] = "John Doe" };

await kvView.PutAsync(transaction: null, key, val);
(IIgniteTuple? value, bool hasValue) = await kvView.GetAsync(transaction: null, key);

Debug.Assert(hasValue);
Debug.Assert(value.FieldCount == 1);
Debug.Assert(value["name"] as string == "John Doe");
cpp
key_value_view<ignite_tuple, ignite_tuple> kv_view = table.get_key_value_binary_view();

ignite_tuple key_tuple{{"id", 42}};
ignite_tuple val_tuple{{"name", "John Doe"}};

kv_view.put(nullptr, key_tuple, val_tuple);
std::optional<ignite_tuple> res_tuple = kv_view.get(nullptr, key_tuple);

assert(res_tuple.has_value());
assert(res_tuple->column_count() == 2);
assert(res_tuple->get<std::int64_t>("id") == 42);
assert(res_tuple->get<std::string>("name") == "John Doe");

4.4.键-值视图

该视图映射到一个业务类型上,可以使用映射到表元组的键对象和值对象来操作表。

java
KeyValueView<AccountKey, Account> kvView = client.tables()
        .table("accounts")
        .keyValueView(AccountKey.class, Account.class);
System.out.println("\nInserting a key-value pair into the 'accounts' table...");

AccountKey key = new AccountKey(123456);

Account value = new Account(
        "Val",
        "Kulichenko",
        100.00d
);

kvView.put(null, key, value);

System.out.println("\nRetrieving a value using KeyValueView API...");

value = kvView.get(null, key);


System.out.println(
        "\nRetrieved value:\n"
            + "    Account Number: " + key.accountNumber + '\n'
            + "    Owner: " + value.firstName + " " + value.lastName + '\n'
            + "    Balance: $" + value.balance);
csharp
IKeyValueView<long, Poco> kvView = table.GetKeyValueView<long, Poco>();

await kvView.PutAsync(transaction: null, 42, new Poco(Id: 0, Name: "John Doe"));
(Poco? value, bool hasValue) = await kvView.GetAsync(transaction: null, 42);

Debug.Assert(hasValue);
Debug.Assert(value.Name == "John Doe");

public record Poco(long Id, string? Name = null);
cpp
key_value_view<person, person> kv_view = table.get_key_value_view<person, person>();

kv_view.put(nullptr, {42}, {"John Doe"});
std::optional<person> res = kv_view.get(nullptr, {42});

assert(res.has_value());
assert(res->id == 42);
assert(res->name == "John Doe");

5.条件查询

Ignite 提供了可用于从表中检索数据的条件查询。条件查询适用于任何类型的视图,并返回正确的数据。

下面的示例显示了如何在隐式事务中执行查询:

java
try (Cursor<Entry<Tuple, Tuple>> cursor = table.keyValueView().query(
        null, // Implicit transaction
        // Query criteria
        and(
                columnValue("name", equalTo("John Doe")),
                columnValue("age", greaterThan(20))
        )
)) {
    // Process query results (keeping original cursor iteration pattern)
    // As an example, println all matched values.
    while (cursor.hasNext()) {
        printRecord(cursor.next());
    }
}

通过使用query()方法指定条件查询,并在columnValue方法中提供比较条件。

还可以指定要执行查询的事务,以便在该事务中执行查询。

java
try (Cursor<Entry<Tuple, Tuple>> cursor = table.keyValueView().query(
        transaction,
        // Query criteria
        and(
                columnValue("name", equalTo("John Doe")),
                columnValue("age", greaterThan(20))
        )
)) {
    // Process query results
    // As an example, println all matched values.
    while (cursor.hasNext()) {
        printRecord(cursor.next());
    }

    // Commit transaction if all operations succeed
    transaction.commit();
} catch (Exception e) {
    // Rollback transaction on error
    transaction.rollback();
    throw new RuntimeException("Transaction failed", e);
}

5.1.异步查询

还可以使用queryAsync方法异步执行查询。这样查询的执行不会阻塞线程。例如可以异步执行上述查询:

java
public static void performQueryAsync(Table table) {
    System.out.println("[ Example 3 ] Performing asynchronous query");

    AsyncCursor<Entry<Tuple, Tuple>> result = table.keyValueView().queryAsync(
                    null, // Implicit transaction
                    and(
                            columnValue("name", equalTo("John Doe")),
                            columnValue("age", greaterThan(20))
                    )
            )
            .join();

    for (Entry<Tuple, Tuple> tupleTupleEntry : result.currentPage()) {
        printRecord(tupleTupleEntry);
    }
}

5.2.比较表达式

条件查询支持以下表达式:

表达式描述示例
equalTo检查对象是否等于该值。columnValue("City", equalTo("New York"))
notEqualTo检查对象是否不等于该值。columnValue("City", notEqualTo("New York"))
greaterThan检查对象是否大于该值。columnValue("Salary", greaterThan(10000))
greaterThanOrEqualTo检查对象是否大于或等于该值。columnValue("Salary", greaterThanOrEqualTo(10000))
lessThan检查对象是否小于该值。columnValue("Salary", lessThan(10000))
lessThanOrEqualTo检查对象是否小于或等于该值。columnValue("Salary", lessThanOrEqualTo(10000))
nullValue检查对象是否为空。columnValue("City", nullValue()
notNullValue检查对象是否不为空。columnValue("City", notNullValue())
in检查对象是否在集合中。columnValue("City", in("New York", "Washington"))
notIn检查对象是否不在集合中。columnValue("City", notIn("New York", "Washington"))

5.3.比较运算符

条件查询支持以下运算符:

表达式描述示例
not取非运算符not(columnValue("City", equalTo("New York")))
and取和运算符and(columnValue("City", equalTo("New York")), columnValue("Salary", greaterThan(10000)))
or取或运算符or(columnValue("City", equalTo("New York")), columnValue("Salary", greaterThan(10000)))

18624049226