一、Redisson 是什么蜀肘?
來(lái)看看百度百科怎么說(shuō)的扮宠。
Redisson是架設(shè)在Redis基礎(chǔ)上的一個(gè)Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(
In-Memory Data Grid
)坛增。【Redis官方推薦】
Redisson在基于NIO的 Netty 框架上薄腻,充分的利用了Redis鍵值數(shù)據(jù)庫(kù)提供的一系列優(yōu)勢(shì),在Java實(shí)用工具包中常用接口的基礎(chǔ)上罢艾,為使用者提供了一系列具有分布式特性的常用工具類昆婿。使得原本作為協(xié)調(diào)單機(jī)多線程并發(fā)程序的工具包獲得了協(xié)調(diào)分布式多機(jī)多線程并發(fā)系統(tǒng)的能力蜓斧,大大降低了設(shè)計(jì)和研發(fā)大規(guī)模分布式系統(tǒng)的難度睁冬。同時(shí)結(jié)合各富特色的分布式服務(wù)豆拨,更進(jìn)一步簡(jiǎn)化了分布式環(huán)境中程序相互之間的協(xié)作施禾。
然后【Redisson官方WiKi】
是這樣說(shuō)的
Redisson 不僅提供了一系列的分布式的Java常用對(duì)象,還提供了許多分布式服務(wù)邮绿。其中包括(
BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service
) Redisson提供了使用Redis的最簡(jiǎn)單和最便捷的方法船逮。Redisson的宗旨是促進(jìn)使用者對(duì)Redis的關(guān)注分離(Separation of Concern)粤铭,從而讓使用者能夠?qū)⒕Ω械胤旁谔幚順I(yè)務(wù)邏輯上。
功能太強(qiáng)大了酱鸭,我都有點(diǎn)不會(huì)用了A堇薄1馐摹!
二捷泞、開(kāi)始使用
1寿谴、導(dǎo)入依賴
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.11.0</version>
</dependency>
2 咏瑟、配置文件配置Redis
Springboot2 中,redis 默認(rèn)用的是lettuce
連接池
spring:
# redis config
redis:
host: 127.0.0.1
password:
port: 6379
database: 0
lettuce:
pool:
max-idle: 8
min-idle: 0
max-active: 8
max-wait: -1ms
timeout: 10000ms
3码泞、配置Redisson
有兩種方法
第一種:程序化配置方法
Config config = new Config();
config.setTransportMode(TransportMode.EPOLL);
config.useClusterServers()
//可以用"rediss://"來(lái)啟用SSL連接
.addNodeAddress("redis://127.0.0.1:7181");
第二種:文件方式配置
// json 文件
Config config = Config.fromJSON(new File("config-file.json"));
RedissonClient redisson = Redisson.create(config);
# yaml 文件
Config config = Config.fromYAML(new File("config-file.yaml"));
RedissonClient redisson = Redisson.create(config);
配置文件的具體內(nèi)容,就不多介紹了悯森,官方的聽(tīng)詳細(xì)的,下面給傳送門(mén)
點(diǎn)我?guī)泔w:傳送門(mén)
我個(gè)人比較喜歡程序化方式,全部代碼如下:
package top.lrshuai.redisson.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
/**
* redisson 配置祝蝠,下面是單節(jié)點(diǎn)配置:
* 官方wiki地址:https://github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95#26-%E5%8D%95redis%E8%8A%82%E7%82%B9%E6%A8%A1%E5%BC%8F
*
*/
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.password}")
private String password;
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
//單節(jié)點(diǎn)
config.useSingleServer().setAddress("redis://" + host + ":" + port);
if(StringUtils.isEmpty(password)){
config.useSingleServer().setPassword(null);
}else{
config.useSingleServer().setPassword(password);
}
//添加主從配置
// config.useMasterSlaveServers().setMasterAddress("").setPassword("").addSlaveAddress(new String[]{"",""});
// 集群模式配置 setScanInterval()掃描間隔時(shí)間绎狭,單位是毫秒, //可以用"rediss://"來(lái)啟用SSL連接
// config.useClusterServers().setScanInterval(2000).addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001").addNodeAddress("redis://127.0.0.1:7002");
return Redisson.create(config);
}
}
以Bean
的方式注入坟岔,然后在想用的地方創(chuàng)建一個(gè)變量即可
4社付、代碼使用Redisson
@Autowired
private RedissonClient redissonClient;
三、Redisson 分布式鎖的簡(jiǎn)單使用
什么是分布式鎖鸥咖?分布式鎖有什么作用啼辣?分布式鎖怎么用?
個(gè)人見(jiàn)解:學(xué)過(guò)多線程的應(yīng)該知道党远,共享變量沟娱,如果不加鎖的話腕柜,當(dāng)多個(gè)線程去操作的時(shí)候就有可能導(dǎo)致數(shù)據(jù)的不一致性等問(wèn)題盏缤。所以Java 本身給我們提供了
Synchronized
關(guān)鍵字或者Lock
鎖,都可以處理這種問(wèn)題。這種方式只針對(duì)單臺(tái)服務(wù)器而言的台舱,像雙十一
柿赊、618
這種大型活動(dòng),肯定不是只有一臺(tái)服務(wù)器就能帶飛的诡蜓,走都不一定能走蔓罚,別說(shuō)飛了。當(dāng)采用分布式系統(tǒng)多臺(tái)服務(wù)器運(yùn)行的時(shí)候郑象,上面的鎖方案就不靠譜了茬末。所以分布式鎖出來(lái)了。
百度百科:
分布式鎖是控制分布式系統(tǒng)之間同步訪問(wèn)共享資源的一種方式辈双。在分布式系統(tǒng)中柜砾,常常需要協(xié)調(diào)他們的動(dòng)作。如果不同的系統(tǒng)或是同一個(gè)系統(tǒng)的不同主機(jī)之間共享了一個(gè)或一組資源证芭,那么訪問(wèn)這些資源的時(shí)候担映,往往需要互斥來(lái)防止彼此干擾來(lái)保證一致性另萤,在這種情況下四敞,便需要使用到分布式鎖忿危。
廢話真多铺厨,代碼擼起
/**
* 如果只有一個(gè)線程來(lái)訪問(wèn),那么在rLock.tryLock() 這個(gè)方法就會(huì)阻塞赃磨,等鎖釋放然后再繼續(xù)下面的操作邻辉,
* 如果是多線程訪問(wèn)值骇,那么在rLock.tryLock() 這個(gè)方法會(huì)直接返回false不阻塞了,繼續(xù)往下執(zhí)行
* 可以配合Jmeter 來(lái)測(cè)試
* 更多鎖的demo,可以參考wiki: https://github.com/redisson/redisson/wiki/8.-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E5%90%8C%E6%AD%A5%E5%99%A8
* @return
*/
@GetMapping("/test")
public Object test(){
//獲取鎖實(shí)例
RLock rLock = redissonClient.getLock(lock);
boolean isLock =false;
try {
// 上鎖
isLock = rLock.tryLock();
System.out.println(Thread.currentThread().getName()+"isLock="+isLock);
if (isLock) {
System.out.println(Thread.currentThread().getName()+"我搶到鎖了吱瘩,開(kāi)心使碾,先休息10秒先");
Thread.sleep(10 *1000);
// todo service 業(yè)務(wù)代碼
}else {
System.out.println(Thread.currentThread().getName()+"被人鎖了皱卓,郁悶下次再來(lái)");
return FAILED;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(isLock){
System.out.println(Thread.currentThread().getName()+"不玩了,開(kāi)鎖了2看D戎!");
// 解鎖
rLock.unlock();
}
}
return SUCCESS;
}
Redisson 提供的鎖有那么幾個(gè)兄朋,按需使用
- 可重入鎖
- 公平鎖
- 聯(lián)鎖
- 紅鎖
- 讀寫(xiě)鎖
- 閉鎖
各個(gè)鎖的使用Wiki 都有介紹掐禁,我只是粗略的開(kāi)個(gè)頭。
四颅和、Redisson消息的發(fā)布訂閱
這個(gè)簡(jiǎn)單傅事,一個(gè)發(fā)布,一個(gè)接受峡扩,簡(jiǎn)單代碼如下:
//發(fā)布
public long publish(MyObjectDTO myObjectDTO){
RTopic rTopic = redissonClient.getTopic(Consts.TopicName);
return rTopic.publish(myObjectDTO);
}
// 訂閱
public void subscribe(){
RTopic rTopic = redissonClient.getTopic(Consts.TopicName);
rTopic.addListener(MyObjectDTO.class, new MessageListener<MyObjectDTO>() {
// 接受訂閱的消息
@Override
public void onMessage(CharSequence charSequence, MyObjectDTO myObjectDTO) {
log.info("接受到消息主題={}蹭越,內(nèi)容={}",charSequence,myObjectDTO);
System.out.println("傳輸?shù)臄?shù)據(jù)為="+myObjectDTO);
}
});
}
MyObjectDTO
就是發(fā)布的消息體,隨意一個(gè)對(duì)象就行,命名有點(diǎn)LOW