線上運(yùn)行一段時(shí)間后就NPE,本地又重現(xiàn)不了培他。一開始以為是框架的bug鹃两,后面發(fā)現(xiàn)還是人為導(dǎo)致的...
場(chǎng)景說明
這里的方法放回null
public Long increment(String key, long i) {
return redisTemplate.opsForValue().increment(key,i);
}
這是另一個(gè)接口,將全局的事務(wù)支持設(shè)置為了true舀凛。非常懷疑是這段代碼導(dǎo)致的怔毛。因?yàn)轫?xiàng)目啟動(dòng)后一段時(shí)間還運(yùn)行良好,過一段時(shí)間就NPE了腾降。
public <T> List<T> rightPop(String key, Class<T> clazz, int num){
Long size = redisTemplate.opsForList().size(key);
if(num > size){
return null;
}
redisTemplate.watch(key);
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.multi();
try {
redisTemplate.opsForList().range(key, 0, num-1);
redisTemplate.opsForList().trim(key, num, -1);
List exec = redisTemplate.exec();
if(null != exec){
List<T> list = (List<T>) exec.get(0);
return list;
}
} catch (Exception e) {
e.printStackTrace();
redisTemplate.discard();
}finally {
redisTemplate.unwatch();
}
return null;
}
懷疑的問題代碼: redisTemplate.setEnableTransactionSupport(true);
查看源碼
在事務(wù)環(huán)境下會(huì)返回null
@return {@literal null} when used in pipeline / transaction.
/**
* Increment an integer value stored as string value under {@code key} by {@code delta}.
*
* @param key must not be {@literal null}.
* @param delta
* @return {@literal null} when used in pipeline / transaction.
* @see <a >Redis Documentation: INCRBY</a>
*/
@Nullable
Long increment(K key, long delta);
但是引發(fā)空指針的這段代碼并沒有顯式地添加redis事務(wù)啊。難不成業(yè)務(wù)方法的 @Transactional傳播過來了碎绎?
重現(xiàn)
test1方法
@GetMapping("/test1")
public void test1() throws IOException {
redisTemplate.watch("1");
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.multi();
try {
redisTemplate.opsForList().range("1", 0, 1-1);
redisTemplate.opsForList().trim("1", 1, -1);
List exec = redisTemplate.exec();
} catch (Exception e) {
}finally {
redisTemplate.unwatch();
}
}
test2方法螃壤,必須加 @Transactional(rollbackFor = Exception.class)注解!筋帖!
@GetMapping("/test2")
public void test2() throws IOException {
productService.test();
}
@Transactional(rollbackFor = Exception.class)
@Override
public void test() {
Long increment = redisTemplate.opsForValue().increment("22", 1);
System.out.println(increment);
}
修正
在finally中關(guān)閉事務(wù)
finally {
redisTemplate.setEnableTransactionSupport(false);
redisTemplate.unwatch();
}
結(jié)論
1奸晴、 @Transactional、redisTemplate.setEnableTransactionSupport(true); 同時(shí)被設(shè)置日麸,那么將以事務(wù)的方式執(zhí)行寄啼,這時(shí)候 opsForValue().increment 返回null
2、redis事務(wù)不要瞎用代箭,有坑的