2014-02-09 3 views
3

Я следую за учебником RetwisJ here. В этом я не думаю, что транзакции Redis реализованы. Например, в следующей функции, если какое-то исключение происходит между ними, данные будут оставлены в несогласованном состоянии. Я хочу знать, как функция как следующий может быть реализована в Spring Data 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); 
    } 

Здесь userIdCounter, valueOps и users инициализируется в конструкторе. Я столкнулся с this в документации (раздел 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 рекомендуется ли или нет.

ответ

1

до SD Redis 1.2 вам придется позаботиться о tansaction обработки самостоятельно, используя TransactionSynchronisationManager

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); 
} 

Пожалуйста, обратите внимание, что один раз в многостадийной, прочитайте операции также будут частью транзакции, что означает, что вы, вероятно, не сможете читать данные с сервера redis. Настройка может отличаться от приведенной выше, поскольку вы могли бы дополнительно позвонить WATCH. Далее вам также придется позаботиться о нескольких обратных вызовах, не отправляя MULTI и/или EXEC более одного раза.

Предстоящий 1.3 RELEASE данных Spring Redis будет поставляться с поддержкой транзакций, управляемых весной, таким образом, чтобы он заботился о MULTi|EXEC|DISCARD, а также позволял выполнять операции чтения (на уже существующих ключах), в то время как синхронизация транзакций активна. Вы уже могли бы дать BUILD-SNAPSHOT вращаться и включить это, установив template.setEnableTransactionSupport(true).

+0

Привет, прошло много времени с тех пор, как это было задано. И поскольку никто не ответил, я понял, как это сделать (обновляется в вопросе). Но я не знаю, рекомендуется ли это для этого. Является ли TransactionSynchronisationManager способом перехода? Требуется ли какая-либо дополнительная конфигурация, кроме этого? Преимущество, которое я нашел в написанном мной коде, если мне нужно прочитать данные из Redis, я могу использовать «шаблон», и поэтому он не будет частью транзакции. – sinu

+1

Использование «SessionCallback» отлично (см. [ссылка] (http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/redis.html#tx)), поскольку это связывает используемое соединение за время, которое команды выполняют для выполнить и освободить его впоследствии. «TransactionSynchronisationManager» или в следующей версии 1.3 «template.setEnableTransactionSupport (true)» скорее предназначен для обработки нескольких вызовов redis, которые потенциально не находятся близко друг к другу, пока активна внешняя транзакция активна.Обычно не нужно напрямую взаимодействовать с TSM. –

Смежные вопросы