用Javascript實現傳送簡訊驗證碼間隔
阿新 • • 發佈:2021-02-09
技術標籤:redisspringboot
一、概念
在redis中沒有隔離級別的概念,都是序列化執行。
事務執行過程:是把事務過程中執行的命令放入佇列中(佇列中的命令要麼都執行,要麼都不執行),輸入exec命令開始執行事務
在redis中,單條命令是原子性執行的,但是事務不能保證原子性,且沒有回滾。事務中任意命令執行失敗,其餘命令仍會被執行。
事務的三個階段:
- 開始事務
- 執行的命令加入佇列
- 執行事務或回滾
事務命令:
- watch key1 key2……:監視一個或多個key,如果事務執行之前,這些key被改動,則事務被打斷。(類似樂觀鎖)
- multi:事務開始
- exec:執行事務(執行後無論事務成功還是失敗,watch加的監控都會被取消掉)
- discard:回滾事務
- unwatch:取消監視
二、redis客戶端如何使用事務
(1)執行事務
(2)回滾事務
(3)事務中異常
1、事務佇列中存在命令錯誤(類似java編譯錯誤),佇列中所有命令都不執行
2、事務佇列中存在語法性錯誤(類似java執行時異常),出錯的命令不執行,其他命令正常執行
(4)使用watch
1、模擬watch k2 中資料未變動,正常執行的過程如下:
2、模擬watch k2 中資料發生變動,導致事務執行失敗,如圖:
事務中途使用其他客戶端修改k2的值,如下:
三、springboot如何使用事務
有兩種方式使用redis事務,手動開啟或自動開啟
redis命令對應的RedisTemplate的方法如下:
RedisTemplate.multi();
RedisTemplate.exec();
RedisTemplate.discard();
RedisTemplate.watch("");
RedisTemplate.unwatch()
(1)手動開啟
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public void test() {
//設定事務支援
stringRedisTemplate.setEnableTransactionSupport(true);
//開啟事務
stringRedisTemplate.multi();
try {
stringRedisTemplate.opsForValue().set("k","v");
stringRedisTemplate.opsForValue().set("k1","v1");
//提交事務
List<Object> exec = stringRedisTemplate.exec();
for (Object o : exec) {
System.out.println(o);
}
} catch (Exception e) {
e.printStackTrace();
//回滾事務
stringRedisTemplate.discard();
}
String k1 = stringRedisTemplate.opsForValue().get("k1");
System.out.println("k1:"+k1);
}
執行結果列印:
(2)自動開啟
1、pom
<!--redis客戶端-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--redis事務依賴JDBC事務管理-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--嵌入式資料庫h2。配置了jdbc必須要配置資料庫,為了方便配置h2。如果專案有mysql的話就不需要h2資料庫了-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
2、啟動類註冊StringRedisTemplate類,並開啟事務支援。
@SpringBootApplication
public class DemoApplication {
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
//開啟事務支援(預設是沒有關閉的)
template.setEnableTransactionSupport(true);
template.setConnectionFactory(redisConnectionFactory);
return template;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
3、controller
@RestController
public class DemoController {
@Autowired
private DemoService demoService;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("/test")
public void getValue() throws Exception {
String k = stringRedisTemplate.opsForValue().get("k1");
System.out.println("k1原值:"+k);
try {
demoService.test();
} catch (Exception e) {
System.out.println("redis事務執行失敗");
}
String k1 = stringRedisTemplate.opsForValue().get("k1");
System.out.println("k1事務之後的值:"+k1);
}
}
4、service
@Service
public class DemoServiceImpl implements DemoService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
@Transactional(rollbackFor = Exception.class)
public void test() throws Exception {
stringRedisTemplate.opsForValue().set("k","v");
stringRedisTemplate.opsForValue().increment("k1");
throw new Exception();
}
}
測試:模擬丟擲異常情況
事務執行失敗,資料沒有被修改