7

我正在关注此处提供的 RetwisJ教程。在这我不认为 Redis 事务被实现。例如,在下面的函数中,如果中间发生一些异常,数据将处于不一致的状态。我想知道如何在Spring Data Redis中将类似以下的功能作为单个事务实现:

public String addUser(String name, String password) {
        String uid = String.valueOf(userIdCounter.incrementAndGet());

        // save user as hash
        // uid -> user
        BoundHashOperations<String, String, String> userOps = template.boundHashOps(KeyUtils.uid(uid));
        userOps.put("name", name);
        userOps.put("pass", password);
        valueOps.set(KeyUtils.user(name), uid);

        users.addFirst(name);
        return addAuth(name);
    }

在这里userIdCountervalueOpsusers在构造函数中被初始化。我在文档中遇到过这个问题(第 4.8 节),但我不知道如何将它放入这个函数中,其中一些变量在函数外部初始化(请不要告诉我必须在每个和我需要交易的每个功能!)。

PS:还有@Transaction可用于 Spring Data Redis 的注释或事务管理器吗?

更新:我尝试过使用MULTI, EXEC。我编写的代码是针对另一个项目的,但是当它应用于这个问题时,它将如下所示:

public String addMyUser(String name, String password) {
        String uid = String.valueOf(userIdCounter.incrementAndGet());
        template.execute(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> operations)
                    throws DataAccessException {
                operations.multi();
                getUserOps(operations, KeyUtils.uid(uid)).put("name", name);
                getUserOps(operations, KeyUtils.uid(uid)).put("pass", password);
                getValueOps(operations).set(KeyUtils.user(name), uid);
                getUserList(operations, KeyUtils.users()).leftPush(name);
                operations.exec();
                return null;
            }
        });
        return addAuth(name);
    }
    private ValueOperations<String, String> getValueOps(RedisOperations operations) {
        return operations.opsForValue();
    }
    private BoundHashOperations<String, String, String> getUserOps(RedisOperations operations, String key) {
        return operations.boundHashOps(key);
    }
    private BoundListOperations<String, String> getUserList(RedisOperations operations, String key) {
        return operations.boundListOps(key);
    }

MULTI请告知是否推荐这种使用方式EXEC

4

1 回答 1

1

在 SD Redis 1.2 之前,您必须使用TransactionSynchronisationManager自行处理事务

上面的代码片段可能看起来像这样:

public String addUser(String name, String password) {

    String uid = String.valueOf(userIdCounter.incrementAndGet());

    // start the transaction
    template.multi(); 

    // register synchronisation
    if(TransactionSynchronisationManager.isActualTransactionActive()) {
        TransactionSynchronisationManager.registerSynchronisation(new TransactionSynchronizationAdapter()) {

            @Override
            public void afterCompletion(int status) {
                switch(status) {
                    case STATUS_COMMITTED : template.exec(); break;
                    case STATUS_ROLLED_BACK : template.discard(); break;
                    default : template.discard(); 
                }
            }
        }
    }

    BoundHashOperations<String, String, String> userOps = template.boundHashOps(KeyUtils.uid(uid));
    userOps.put("name", name);
    userOps.put("pass", password);
    valueOps.set(KeyUtils.user(name), uid);

    users.addFirst(name);

    return addAuth(name);
}

请注意,一旦在 multi 中,读取操作也将成为事务的一部分,这意味着您可能无法从 redis 服务器读取数据。设置可能与上述设置不同,因为您可能需要另外调用WATCH. 此外,您还必须注意多个回调不发送MULTI和/或EXEC不止一次。

即将发布的 Spring Data Redis 1.3 RELEASE 将提供对 Spring 托管事务的支持,以在事务同步处于活动状态时照顾MULTi|EXEC|DISCARD并允许读取操作(在现有密钥上)。您已经可以给 BUILD-SNAPSHOT 一个旋转并通过设置打开它template.setEnableTransactionSupport(true)

于 2014-04-28T08:00:32.963 回答