redis事务
SpringBoot开启Redis事务错误: Cannot use Jedis when in Multi. Please use Transaction or reset jedis state.
watch key1 key2 ... : 监视一或多个key,如果在事务执行之前,
被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 )
multi : 标记一个事务块的开始( queued )
exec : 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 )
discard : 取消事务,放弃事务块中的所有命令
unwatch : 取消watch对所有key的监控
watch指令类似于乐观锁,在事务提交时,如果watch监控的多个KEY中任何KEY的值已经被其他客户端更改,则使用EXEC执行事务时,事务队列将不会被执行,同时返回Nullmulti-bulk应答以通知调用者事务执行失败。
实战:
@Autowired
private StringRedisTemplate stringRedisTemplate;
public Object execTransactionCorrect() {
// watch该key,如果提交事物时有外界调整则设置失败
String key = "redis";
// 开始设置key为100
stringRedisTemplate.opsForValue().set(key, "100");
return stringRedisTemplate.execute(new SessionCallback<String>() {
@Override
public <K, V> String execute(RedisOperations<K, V> operations) throws DataAccessException {
try {
operations.watch((K) key);
// 开启事务
operations.multi();
// 修改数据
operations.opsForValue().set((K)key, (V)"2");
// operations.opsForValue().increment((K) key);
// 模拟异常
Integer.parseInt("a");
// 提交事物 之前的redis操作,
operations.exec();
} catch (Exception e) {
e.printStackTrace();
// 出现异常则需要取消redis事务(不用回滚,因为multi之后,相当于资料)
operations.discard();
}
return (String) operations.opsForValue().get(key);
}
});
}
springboot手动开启事务
//1,注入bean
@Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
//2,结合try-catch使用
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
try {
dosomething....
platformTransactionManager.commit(transactionStatus);
} catch (Exception e) {
platformTransactionManager.rollback(transactionStatus);
}
@Autowired
DataSourceTransactionManager txm;
@Override
public void test() {
TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
TransactionStatus status = txm.getTransaction(transactionDefinition);
this.insert(new PeopleHouseInfoEntity().setRoom("123131"));
int a = 10 / 0;
// txm.rollback(status);
txm.commit(status);
}
全局切面配置,比注解中优先级高。
package com.yymt.common.config;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@Aspect
//切面
//表示该类相当于Spring的xml配置文件中的<Beans>
@Configuration
public class TransactionAdviceConfig {
/**
* 定义切点路径
*/
private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.yymt.service..*.impl.*.*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
/**
* @description 事务管理配置
*/
@Bean
public TransactionInterceptor TxAdvice() {
// 事务管理规则,承载需要进行事务管理的方法名(模糊匹配)及设置的事务管理属性
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
// 设置第一个事务管理的模式(适用于“增删改”)
RuleBasedTransactionAttribute transactionAttribute1 = new RuleBasedTransactionAttribute();
// 当抛出设置的对应异常后,进行事务回滚(此处设置为“Exception”级别)
transactionAttribute1.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
// 设置隔离级别(存在事务则加入其中,不存在则新建事务)
transactionAttribute1.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 设置传播行为(读已提交的数据)
transactionAttribute1.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
// 设置第二个事务管理的模式(适用于“查”)
RuleBasedTransactionAttribute transactionAttribute2 = new RuleBasedTransactionAttribute();
// 当抛出设置的对应异常后,进行事务回滚(此处设置为“Exception”级别)
transactionAttribute2.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
// 设置隔离级别(存在事务则挂起该事务,执行当前逻辑,结束后再恢复上下文事务) 。xl:挂起后会导致本次插入的数据查询不到()
transactionAttribute2.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
// transactionAttribute2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 设置传播行为(读已提交的数据)
transactionAttribute2.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
// 设置事务是否“只读”(非必需,只是声明该事务中不会进行修改数据库的操作,可减轻由事务造成的数据库压力,属于性能优化的推荐配置)
transactionAttribute2.setReadOnly(true);
// 建立一个map,用来储存要需要进行事务管理的方法名(模糊匹配)
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("insert*", transactionAttribute1);
txMap.put("add*", transactionAttribute1);
txMap.put("send*", transactionAttribute1);
txMap.put("save*", transactionAttribute1);
txMap.put("update*", transactionAttribute1);
txMap.put("modify*", transactionAttribute1);
txMap.put("change*", transactionAttribute1);
txMap.put("delete*", transactionAttribute1);
txMap.put("remove*", transactionAttribute1);
txMap.put("check*", transactionAttribute1);
txMap.put("upload*", transactionAttribute1);
txMap.put("export*", transactionAttribute1);
txMap.put("create*", transactionAttribute1);
txMap.put("download*", transactionAttribute1);
txMap.put("query*", transactionAttribute2);
txMap.put("get*", transactionAttribute2);
txMap.put("select*", transactionAttribute2);
txMap.put("find*", transactionAttribute2);
// 注入设置好的map
source.setNameMap(txMap);
// 实例化事务拦截器
TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
return txAdvice;
}
/**
* @description 利用AspectJExpressionPointcut设置切面
*/
@Bean
public Advisor txAdviceAdvisor() {
// 声明切点要切入的面
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
// 设置需要被拦截的路径
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
// 设置切面和配置好的事务管理
return new DefaultPointcutAdvisor(pointcut, TxAdvice());
}
}