Java 如何以干净的方式在SpringDataRedis中实现事务?

Java 如何以干净的方式在SpringDataRedis中实现事务?,java,spring,redis,spring-data-redis,Java,Spring,Redis,Spring Data Redis,我正在学习可用的RetwisJ教程。在这种情况下,我认为没有实现Redis事务。例如,在下面的函数中,如果在这两个函数之间发生异常,数据将保持不一致状态。 我想知道如何在Spring Data Redis中作为单个事务实现以下功能: public String addUser(String name, String password) { String uid = String.valueOf(userIdCounter.incrementAndGet());

我正在学习可用的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);
    }

请说明是否推荐使用
MULTI
EXEC

在SD Redis 1.2之前,您必须使用

上面的snipplet可能看起来像这样:

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);
}
publicstringadduser(字符串名称、字符串密码){
String uid=String.valueOf(userIdCounter.incrementAndGet());
//启动事务
multi()模板;
//寄存器同步
if(TransactionSynchronizationManager.isActualTransactionActive()){
TransactionSynchronizationManager.RegisterSynchronization(新TransactionSynchronizationAdapter()){
@凌驾
完成后公共作废(int状态){
开关(状态){
案例状态_已提交:template.exec();中断;
案例状态_回滚:template.discard();break;
默认值:template.discard();
}
}
}
}
BoundHashOperations userOps=template.boundHashOps(KeyUtils.uid(uid));
userOps.put(“name”,name);
userOps.put(“pass”,密码);
valueOps.set(KeyUtils.user(name),uid);
users.addFirst(name);
返回addAuth(name);
}
请注意,多次读取操作也将是事务的一部分,这意味着您可能无法从redis服务器读取数据。 设置可能与上述设置不同,因为您可能需要另外调用
WATCH
。此外,您还必须处理多个回调,不要多次发送
MULTI
和/或
EXEC


即将发布的Spring Data Redis 1.3版将支持Spring管理的事务,在事务同步处于活动状态时,支持
MULTi | EXEC | DISCARD
并允许读取操作(在现有密钥上)。您已经可以对构建快照进行旋转,并通过设置
模板来启用此功能。setEnableTransactionSupport(true)

您好,很久没有提出此问题了。由于没有人回答,我想出了怎么做(在问题中更新)。但我不知道这是否是推荐的方法。TransactionSynchronizationManager是一条出路吗?它是否需要除此之外的任何其他配置?我在我编写的代码中发现的优点是,如果我必须从Redis读取数据,我可以使用“模板”,因此它不会成为事务的一部分。使用
SessionCallback
非常好(请参见),因为这会在命令执行时绑定已使用的连接,然后释放它。
TransactionSynchronizationManager
或在下一版本1.3
模板中。setEnableTransactionSupport(true)
更适合处理对redis的多个调用,这些调用在外部事务处于活动状态时可能不在同一位置。通常情况下,用户不必直接与TSM交互。@Christofstrobl:我也有类似的情况。我已经搜索了文档,但我没有看到任何关于我们如何保证交易的参考资料。一旦抛出任何异常,正确配置的RestTemplate是否应该回滚?假设我们在Spring服务中有一个方法:
@Transactional public void doSomth(){redisTemplate.delete(…);redisTemplate.delete(…);}
它是否应该正常回滚第一次删除,第二次将失败?
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);
}