Redisのピット:spring-data-redisのRedisトランザクション


Redisのピット:spring-data-redisのRedisトランザクションRedisのピット:RedisトランザクションRedisのピットを理解する:RedisとMySQLのトランザクションの区別Transactionのピット:データベーストランザクションTransactionのピット:SpringのTransactionの構成と非構成の区別Transactionのピット:sql実行結果を分析し、トランザクションrollbackをアクティブに促す
SessionCallback Redisは、multiexec、またはdiscardコマンドによってトランザクションサポートを提供し、これらのアクションはRedisTemplateでも同様に利用可能である.ただし、RedisTemplateではRedisCallBackインタフェースがデフォルトで使用されており、同じ接続を使用して同じトランザクション内のすべての操作を実行することは保証されていません(この場合、Transactionは無効です).
さらに、Spring Data Redisは、 が複数の動作を実行することを保証する必要がある場合、例えば「Redis を使用する必要がある場合」に使用するためのSessionCallbackインターフェースを提供する.次のように見えます.
public  T execute(SessionCallback session) {
		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
		Assert.notNull(session, "Callback object must not be null");

		RedisConnectionFactory factory = getConnectionFactory();
		// bind connection
		RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);// 8 
		try {
			return session.execute(this);
		} finally {
			RedisConnectionUtils.unbindConnection(factory);
		}
	}
  • RedisTemplate.execute(SessionCallback session)方法の 8 はすでに をした.

  • 使用方法は次のとおりです.
    //execute a 
         
          transaction
         
    List<
         
          Object
         > txResults = redisTemplate.
         
          execute
         (new 
         
          SessionCallback
         <List<
         
          Object
         >>() {
      
         
          public
          List<
         
          Object
         > 
         
          execute
         (RedisOperations operations) 
         
          throws
          DataAccessException {
        operations.
         
          multi
         ();
        operations.
         
          opsForSet
         ().add("key", "value1");
    
        // 
         
          This
          
         
          will
          
         
          contain
          
         
          the
          
         
          results
          of 
         
          all
          
         
          ops
          in 
         
          the
          
         
          transaction
         
        
         
          return
          operations.
         
          exec
         ();
      }
    });
    System.out.
         
          println
         ("
         
          Number
          of 
         
          items
          
         
          added
          to 
         
          set
         : " + txResults.get(0));
    

    戻る前に、RedisTemplateはそのvalue、hash key、hash valueシーケンサを使用してexecのすべての結果を逆シーケンス化します.トランザクション結果にカスタムシーケンス化器を渡す追加のexecメソッド.
    @Transactionalサポート
    以上、セッションCallback によって、multiexec、またはdiscardを実現することによって、Redis をサポートすることができるが、これは複雑であり、Redis (opsXXX.X)が実行する位置にも限界がある(機能に影響を及ぼさないが).しかし、Springでは、2ステップでより簡単にできます.
  • は、methodに注記**@TransactionalまたはXml構成*()を追加し、トランザクション・接点を登録します.TransactionSynchronizationManagerを呼び出すことに相当します.setActualTransactionActive ( true );
  • setEnableTransactionSupport(true)によりRedisTemplateインスタンスの (デフォルトでは無効)
  • を明示的に有効にする.
    /** Sample Configuration **/
    @Configuration
    public class RedisTxContextConfiguration {
      @Bean
      public StringRedisTemplate redisTemplate() {
        StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory());
        // explicitly enable transaction support
        template.setEnableTransactionSupport(true);
        return template;
      }
    }
    

    redisTemplateインスタンスは、デフォルトでexecute(RedisCallback action)を呼び出します.メソッドの内容は次のとおりです.
    
         
          public
          <T> T 
         
          execute
         (RedisCallback<T> action, 
         
          boolean
          exposeConnection, 
         
          boolean
          pipeline){
    		/**
    		 *        ……
    		 */
    		try {
    			if (enableTransactionSupport) {
    				// 
         
          only
          
         
          bind
          
         
          resources
          in 
         
          case
          of 
         
          potential
          
         
          transaction
          
         
          synchronization
         
    				conn = RedisConnectionUtils.
         
          bindConnection
         (factory, enableTransactionSupport);
    			} 
         
          else
          {
    				conn = RedisConnectionUtils.
         
          getConnection
         (factory);
    			}
    		/**
    		 *     ……
    		 */
    }
    
    
         
          public
          
         
          static
          RedisConnection 
         
          bindConnection
         (RedisConnectionFactory factory, 
    			
         
          boolean
          enableTransactionSupport) {
    		/**
    		 *    ……
    		 */
    		RedisConnection conn = factory.
         
          getConnection
         ();
    		RedisConnection connectionToBind = conn;
    		//redisTemplate      ,  transactionManager           
    		if (enableTransactionSupport && 
         
          isActualNonReadonlyTransactionActive
         ()) {
    			connectionToBind = 
         
          createConnectionProxy
         (conn, factory);
    		}
    		/**
    		 *    ……
    		 */
    		
         
          return
          conn;
    }
    

    enableTransactionSupport=trueは、現在のThreadRedisConnectionをバインドしようとします.接続は、isActualNonReadonlyTransactionActive=trueである場合にのみ正常にバインドされます.
    接続バインディングに成功し、MULTIがトリガーされます.MULTIが呼び出されると、
  • 現在のRedisConnectionwrite に並びます.
  • すべてのreadonly 、例えばKEYSは、新しい(非Threadバインド)RedisConnectionに配布される.
  • コマンドEXECまたはDISCARD SpringAOPの動的プロキシオブジェクトに渡す呼び出し:
  • プロセス中に (デフォルトのRuntimeExceptionおよびそのサブクラス)がない場合、EXECが呼び出され、コマンドキューが実行される.
  • そうでなければDISCARD、コマンドキューをクリアします.

  • トランザクションサポートを有効にすると、次のようになります.
    /** Usage Constrainsts **/
    // 
         
          executed
          on 
         
          thread
          
         
          bound
          
         
          connection
         
    template.
         
          opsForValue
         ().set("foo", "bar");
    
    // 
         
          read
          
         
          operation
          
         
          executed
          on a 
         
          free
          (
         
          not
          tx-
         
          aware
         )
    connection template.
         
          keys
         ("*");
    
    // 
         
          returns
          
         
          null
          as 
         
          values
          
         
          set
          
         
          within
          
         
          transaction
          
         
          are
          
         
          not
          
         
          visible
         
    template.
         
          opsForValue
         ().get("foo");
    

    上記のサンプルコードはSpring公式サイトから与えられ、3番目は明らかにWATCHコマンドが を開いた後の結果である.しかし、少なくとも本人が使用しているspring-data-redis-1.8.10では.RELEASE . JArでは、
    <
          
           dependency
          >
    	<
          
           groupId
          >org.springframework.data
          
           groupId
          >
    	<
          
           artifactId
          >spring-data-redis
          
           artifactId
          >
    	<
          
           version
          >1.8.10.RELEASE
          
           version
          >
    
          
           dependency
          >
    
    WATCHコマンドは使用されていません.親測定 の効果は存在しません(自分の依存バージョンに基づいて試してみてください).ここにコードが表示されます.
  • org.springframework.data.redis.core.RedisConnectionUtils.potentiallyRegisterTransactionSynchronisation
  • 
         
          private
          
         
          static
          
         
          void
          
         
          potentiallyRegisterTransactionSynchronisation
         (RedisConnectionHolder connHolder,
    			
         
          final
          RedisConnectionFactory factory) {
    
    		if (
         
          isActualNonReadonlyTransactionActive
         ()) {
    
    			if (!connHolder.
         
          isTransactionSyncronisationActive
         ()) {
    				connHolder.
         
          setTransactionSyncronisationActive
         (
         
          true
         );
    
    				RedisConnection conn = connHolder.
         
          getConnection
         ();
    				conn.
         
          multi
         ();//    conn.watch()    
    
    				TransactionSynchronizationManager.
         
          registerSynchronization
         (new 
         
          RedisTransactionSynchronizer
         (connHolder, conn,
    						factory));
    			}
    		}
    	}
    

    宣言 RedisTemplateインスタンス
    2つのRedisTemplate例?
  • サポートトランザクション:commandsまたは 、または 、データ整合性の維持.
  • はトランザクションをサポートせず、commandは直ちに実行され、 に即時に戻り、さらに に戻る.
  • /** 
         
          Sample
          
         
          Configuration
          **/
    @Configuration
    
         
          public
          
         
          class
          
         
          RedisTxContextConfiguration
          {
      @Bean
      
         
          public
          StringRedisTemplate 
         
          redisTransactionTemplate
         () {
        StringRedisTemplate template = new 
         
          StringRedisTemplate
         (
         
          redisConnectionFactory
         ());
        // 
         
          explicitly
          
         
          enable
          
         
          transaction
          
         
          support
         
        template.
         
          setEnableTransactionSupport
         (
         
          true
         );
        
         
          return
          template;
      }
     @Bean
      
         
          public
          StringRedisTemplate 
         
          redisTemplate
         () {
        StringRedisTemplate template = new 
         
          StringRedisTemplate
         (
         
          redisConnectionFactory
         ());
        
         
          return
          template;
      }
    }