在java

时间:2016-07-25 18:42:51

标签: java cassandra mapping

好的,所以我有一个有趣的问题。我正在使用java / maven / spring-boot / cassandra ...我正在尝试创建他们使用的Mapper设置的动态实例化。 即。

//Users.java
import com.datastax.driver.mapping.annotations.Table;

@Table(keyspace="mykeyspace", name="users")
public class Users {
    @PartitionKey
    public UUID id;
    //...
}

现在,为了使用它,我必须明确地说......

Users user = (DB).mapper(Users.class);

显然用我的db类替换(DB)。 这是一个很棒的模型,但我遇到了代码重复的问题。我的Cassandra数据库有2个键空间,两个键空间都有完全相同的表,表中的列完全相同(这不是我的选择,根据我的公司,这绝对是必须的)。因此,当我需要根据表单提交访问其中一个时,它会变成一堆重复的代码,例如:

//myWebController.java
import ...;

@RestController
public class MyRestController {

@RequestMapping(value="/orders", method=RequestMethod.POST)
public string getOrders(...) {
    if(Objects.equals(client, "first_client_name") {
        //do all the things to get first keyspace objects like....
        FirstClientUsers users = (db).Mapper(FirstClientUsers.class);
        //...
    } else if(Objects.equals(client, "second_client_name") {
        SecondClientUsers users = (db).Mapper(SecondClientUsers.class);
        //....
    }
    return "";
}

我一直在尝试使用像......这样的方法

Class cls = Class.forName(STRING_INPUT_VARIABLE_HERE);

这适用于基类,但是当尝试使用Accessor时,它不再有效,因为Accessors必须是接口,因此当你执行Class cls时,它不再是接口。

我正在尝试找到有关如何动态完成此工作的任何其他解决方案,而不必为每个可能的客户端都有重复的代码。每个客户端在Cassandra中都有自己的命名空间,与其他所有客户端完全相同。

我无法更改数据库模型,这是一个必须根据公司。 使用PHP这非常简单,因为它不关心类型转换,我可以很容易地做...

function getData($name) {
    $className = $name . 'Accessor';
    $class = new $className();
}

和poof我有一个动态类,但我遇到的问题是Type规范,我必须明确说...

FirstClientUsers users = new FirstClientUsers();
//or even
FirstClientUsers users = Class.forName("FirstClientUsers");

我希望这是有道理的,我无法想象我是第一个遇到这个问题的人,但我找不到任何在线解决方案。所以我真的希望有人知道如何在不重复我们拥有的每个键空间完全相同的逻辑的情况下完成这项工作。它使代码无法维护且不必要地长。

提前感谢您提供任何帮助。

1 个答案:

答案 0 :(得分:1)

不要在模型类中指定键空间,而是使用所谓的“每个键空间会话”模式。

您的模型类看起来像这样(请注意,键空间未定义):

@Table(name = "users")
public class Users {
    @PartitionKey
    public UUID id;
    //...
}

您的初始化代码将具有以下内容:

Map<String, Mapper<Users>> mappers = new ConcurrentHashMap<String, Mapper<Users>>();

Cluster cluster = ...;

Session firstClientSession = cluster.connect("keyspace_first_client");
Session secondClientSession = cluster.connect("keyspace_second_client");

MappingManager firstClientManager = new MappingManager(firstClientSession);
MappingManager secondClientManager = new MappingManager(secondClientSession);

mappers.put("first_client", firstClientManager.mapper(Users.class));
mappers.put("second_client", secondClientManager.mapper(Users.class));

// etc. for all clients

然后,您将存储mappers对象,并通过依赖注入将其提供给应用程序中的其他组件。

最后,您的REST服务将如下所示:

import ...

@RestController
public class MyRestController {

    @javax.inject.Inject
    private Map<String, Mapper<Users>> mappers;

    @RequestMapping(value = "/orders", method = RequestMethod.POST)
    public string getOrders(...) {
        Mapper<Users> usersMapper = getUsersMapperForClient(client);
        // process the request with the right client's mapper
    }

    private Mapper<Users> getUsersMapperForClient(String client) {
        if (mappers.containsKey(client))
            return mappers.get(client);
        throw new RuntimeException("Unknown client: " + client);
    }
}

注意如何注入mappers对象。

小尼:我会以单数形式命名您的班级User,而不是Users(复数形式)。