首页 > 解决方案 > 有没有办法可以插入地图使用 QueryBuilder 在 Cassandra 表上创建动态表(没有模型类的表)

问题描述

public int save(String tableName, Map<String, Object> dataMap) throws IllegalAccessException {
    SimpleStatement saveStatement = QueryBuilder.insertInto(tableName).values()
            



    return 1;

}

我已经尝试过 QueryBuilder 的其他内置方法来将地图值作为一个整体保存,但如果使用“values()”方法并且我已经有一个 map<String,则只能使用 map<String,Term> 类型的地图来保存数据,Object>。这需要为动态表完成 ps 我对动态表不太熟悉。我尝试使用返回类型整数的另一种方法是

public int save(String tableName, Map<String, Object> dataMap) throws IllegalAccessException {



    SimpleStatement updateStatement = QueryBuilder.update(tableName)
            .set(appendSet(dataMap))
            .where(appendWhere(domainId))
            .build();
    log.info(updateStatement.getQuery());

    return 1;
}
private Iterable<Assignment> appendSet(Map<String, Object> dataMap) throws IllegalAccessException {
    List<Assignment> assignments = new ArrayList<>();
    for (Field field : dataMap.getClass().getDeclaredFields()) {
        if (!field.getName().equals("key")) {
            try {
                field.setAccessible(true);
                if (field.get(dataMap) != null) {
                    if (field.getType().equals(Long.class)) {
                        assignments.add(Assignment.setColumn(field.getName(), literal(Long.valueOf(field.get(dataMap).toString()))));
                    } else {
                        assignments.add(Assignment.setColumn(field.getName(), literal(field.get(dataMap))));
                    }
                }
            } catch (IllegalAccessException e) {
                log.catching(e);
            }
        }
    }
    return assignments;
}

private Iterable<Relation> appendWhere(Object key) {
    List<Relation> relations = new ArrayList<>();
    for (Field field : key.getClass().getDeclaredFields()) {
        try {
            field.setAccessible(true);
            if (field.get(key) != null) {
                if (field.getType().equals(Long.class)) {
                    relations.add(Relation.column(field.getName()).isEqualTo(literal(Long.valueOf(field.get(key).toString()))));
                } else {
                    relations.add(Relation.column(field.getName()).isEqualTo(literal(field.get(key))));
                }
            }
        } catch (IllegalAccessException e) {
            log.catching(e);
        }
    }
    return relations;
}

这可能也没有成功。我需要使用 save 方法返回一个整数,但我无法弄清楚如何使用 QueryBuilders 或 CassandraTemplate 将映射值插入到 cassandra 表本身。我正在使用 Cassandra 数据库,我的表是动态的。谁能给我推荐一篇好文章或任何东西?我找到了文章,但那些并没有帮助我将映射键值对插入表中,所以我很挣扎。任何帮助,将不胜感激。

标签: spring-bootcassandraquery-builderdynamic-tables

解决方案


Cassandra 数据建模提醒

Cassandra 没有动态表之类的东西,它使用严格的模式。我会争辩说,如果你没有找到任何样本,那是因为它是一种反模式。

使用 Cassandra 数据库,您首先要设计查询,然后才定义表,因为**您只能过滤主键中的字段(where 子句的一部分)。我提到这Iterable<Relation> appendWhere(Object key)很可疑,Cassandra 中没有连接或关系。

如果在相同数据上出现新查询,则将数据复制到另一个表中(是的,对于关系型或面向文档的情况不同)

在您的应用程序初始化时,您prepare的(静态)语句用于验证语法并PrepareStatementID与服务器共享。

@PostConstruct
public void prepareStatements() {
   PreparedStatement  stmtCreateUser = 
   session.prepare(QueryBuilder.insertInto(USER_TABLENAME)
                .value(USER_EMAIL, QueryBuilder.bindMarker())
                .value(USER_FIRSTNAME, QueryBuilder.bindMarker())
                .value(USER_LASTNAME, QueryBuilder.bindMarker())
                .ifNotExists().build());
}

^ 注意定义中使用的常量。稍后,当您为额外的表重用列名或重命名列时,调试起来会更容易。

给定一张桌子:

CREATE TABLE IF NOT EXISTS users_by_city (
    city name,
    firstname text,
    lastname text,
    email text,
    PRIMARY KEY ((city), lastname, firstname, email)
);

合法但不推荐:

// This query is legal but never forget the where clause or you do full scan cluster
SELECT [fields] FROM users_by_city;

// This query is legal as you provide the partition in the where clause but having * in the select is hazardous if columns are added later.
SELECT * FROM users_by_city WHERE city=?

法律查询

SELECT firstname,lastname,email FROM users_by_city WHERE city=?

SELECT firstname,email FROM users_by_city WHERE city=? and lastname=?

// order is important
SELECT firstname,email FROM users_by_city WHERE city=? and lastname=? and firstname=?

非法查询

// city is required in PK
SELECT firstname,email FROM users_by_city WHERE lastname=? and firstname=?

// order of cluster columns are important
SELECT firstname,email FROM users_by_city WHERE a city=?  and firstname=?

实施细节

有了所有这些提醒(抱歉,如果您已经知道以后可能会提出问题的人的所有这些想法......)这里有一些想法。

QueryBuilder已经是动态构建查询的构建器,但是查看您可以想到的代码

插入

public SimpleStatement insertInto(String keyspace, 
  String tableName, Map<String, Object> fields) {
  return QueryBuilder.insertInto(keyspace, tableName)
                     .values(fields.entrySet()
                         .stream().collect(Collectors.toMap(
                             entry -> entry.getKey(), 
                             entry -> QueryBuilder.literal(entry.getValue()))))
                     .build();
}

选择

public SimpleStatement selectFrom(String keyspace, String tableName, Map<String, Relation> fields) {
        return QueryBuilder.selectFrom(keyspace, tableName)
                           .columns(fields.keySet())
                           .where(fields.values())
                           .build();
        
    }

额外资源


推荐阅读