使用Java代碼實(shí)現(xiàn)Redis和數(shù)據(jù)庫(kù)數(shù)據(jù)同步
這里我用到了Redis當(dāng)中的發(fā)布訂閱模式實(shí)現(xiàn)(JAVA代碼實(shí)現(xiàn))
先看圖示

下面為代碼實(shí)現(xiàn)
首先將RedisMessageListenerContainer交給Spring管理.
@Configuration
public class redisConfig {
@Autowired
RedisConnectionFactory redisConnectionFactory;
@Autowired
@Qualifier("carServiceDb")
private CarService carService;//操作數(shù)據(jù)庫(kù)
@Bean
public RedisMessageListenerContainer listenerContainer(){
//創(chuàng)建一個(gè)Redis消息監(jiān)聽(tīng)器容器對(duì)象
RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer();
//設(shè)置Redis連接工廠(chǎng)對(duì)象
listenerContainer.setConnectionFactory(redisConnectionFactory);
//向監(jiān)聽(tīng)器容器中添加一個(gè)監(jiān)聽(tīng)器,該監(jiān)聽(tīng)器的主題為INSERTED
listenerContainer.addMessageListener(new MessageListener() {
@Override
public void onMessage(Message message, byte[] pattern) {
System.out.println("*************insert*************");
String carJsonStr = new String(message.getBody());
Car car = JSONObject.parseObject(carJsonStr, Car.class);
carService.addCar(car);
System.out.println(new String(message.getBody()));
System.out.println(new String(pattern));
System.out.println("*************insert*************");
}
}, new ChannelTopic(ChannelEnum.INSERTED.name()));
//向監(jiān)聽(tīng)器容器中添加一個(gè)監(jiān)聽(tīng)器,該監(jiān)聽(tīng)器的主題為UPDATED
listenerContainer.addMessageListener(new MessageListener() {
@Override
public void onMessage(Message message, byte[] pattern) {
System.out.println("*************UPDATED*************");
String carJsonStr = new String(message.getBody());
Car car = JSONObject.parseObject(carJsonStr, Car.class);
carService.updataCount(car.getBookId(),car.getNumber(),car.getUserId());
System.out.println(new String(message.getBody()));
System.out.println(new String(pattern));
System.out.println("*************UPDATED*************");
}
}, new ChannelTopic(ChannelEnum.UPDATED.name()));
//向監(jiān)聽(tīng)器容器中添加一個(gè)監(jiān)聽(tīng)器,該監(jiān)聽(tīng)器的主題為DELETED
listenerContainer.addMessageListener(new MessageListener() {
@Override
public void onMessage(Message message, byte[] pattern) {
System.out.println("*************DELETED*************");
System.out.println(new String(message.getBody()));
System.out.println(new String(pattern));
List<String[]> strings = JSONArray.parseArray(new String(message.getBody()), String[].class);
String[] bookIds = strings.get(0);
String userId = strings.get(1)[0];
carService.delCar(bookIds,userId);
System.out.println("----------------------");
System.out.println(Arrays.toString(bookIds));
System.out.println(userId);
System.out.println("--------delete--------");
System.out.println("*************DELETED*************");
}
}, new ChannelTopic(ChannelEnum.DELETED.name()));
return listenerContainer;
}
}下面代碼中的 stringRedisTemplate.convertAndSend();就是發(fā)送消息的,其中參數(shù)1是發(fā)送消息的名稱(chēng),參數(shù)2是發(fā)送消息的內(nèi)容
@Service("carService")
@Slf4j
public class CarServiceImpl extends ServiceImpl<CarMapper, Car> implements CarService {
//購(gòu)物車(chē)hash的Key
public static final String CAR_KEY = "carKey";
//hash購(gòu)物車(chē)中field的前綴
public static final String USER_CAR_HASH_FIELD_PREFIX = "car::";
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 這里存儲(chǔ)的時(shí)候采用Redis當(dāng)中的hash存儲(chǔ)
*
* @param car
*/
@Override
@Synchronized
public void addCar(Car car) {
//這里存儲(chǔ)的時(shí)候采用Redis當(dāng)中的hash存儲(chǔ)
HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
//這里field為CAR_HASH_FIELD
String userCarKey = USER_CAR_HASH_FIELD_PREFIX + car.getUserId();
//Map<String,Car> 鍵(存儲(chǔ)bookId) 值存儲(chǔ)購(gòu)物車(chē)某一個(gè)商品的信息
Map<String, Car> CarMap = null;
boolean flag = true;
//獲得Redis中以存儲(chǔ)的當(dāng)前用戶(hù)的購(gòu)物車(chē)信息
if (opsForHash.hasKey(CAR_KEY, userCarKey)) {
//存在當(dāng)前用戶(hù)的購(gòu)物車(chē)信息,那么獲取原有的數(shù)據(jù)
String carMapJson = opsForHash.get(CAR_KEY, userCarKey);
CarMap = JSONObject.parseObject(carMapJson, new TypeReference<Map<String, Car>>() {
});
//檢測(cè)當(dāng)前購(gòu)物車(chē)信息中是否包含新添加上的商品,如果包含則更新數(shù)量,如果不包含才新增
if (CarMap.containsKey(car.getBookId())) {
//獲取原先商品的數(shù)量
Integer BeforeNumber = CarMap.get(car.getBookId()).getNumber();
log.info("BeforeNumber==============>{}", BeforeNumber);
Integer nowNumber = car.getNumber(); //前端傳過(guò)來(lái)現(xiàn)在的
log.info("nowNumber==============>{}", nowNumber);
CarMap.get(car.getBookId()).setNumber(BeforeNumber + nowNumber);
flag = false; //存在商品
//修改
//包含才新增 圖書(shū)的數(shù)量 在原有的基礎(chǔ)上新增圖書(shū)的數(shù)量
} else {
//新增
//如果不包含當(dāng)前商品信息 那么直接將商品添加到購(gòu)物車(chē)信息當(dāng)中
CarMap.put(car.getBookId(), car);
}
} else {
/* 新增
*
* 當(dāng)前的用戶(hù)的購(gòu)物車(chē)信息不存在
* 首先把其添加的商品首先存儲(chǔ)到CarMap中
* */
CarMap = new HashMap<>();
CarMap.put(car.getBookId(), car);
}
//最后將其存入redis當(dāng)中
opsForHash.put(CAR_KEY, userCarKey, JSONObject.toJSONString(CarMap));
if (flag){
//新增
stringRedisTemplate.convertAndSend(ChannelEnum.INSERTED.name(), JSONObject.toJSONString(CarMap.get(car.getBookId())));
}else {
//修改
stringRedisTemplate.convertAndSend(ChannelEnum.UPDATED.name(), JSONObject.toJSONString(CarMap.get(car.getBookId())));
}
}
@Override
public Collection<Car> getCarList(String userId) {
//這里存儲(chǔ)的時(shí)候采用Redis當(dāng)中的hash存儲(chǔ)
HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
String userCarKey = USER_CAR_HASH_FIELD_PREFIX + userId;
String jsonStr = opsForHash.get(CAR_KEY, userCarKey);
Map<String,Car> CarMap = JSONObject.parseObject(jsonStr, Map.class);
return CarMap.values();
}
@Override
public void updataCount(String bookId, int number, String userId) {
//這里存儲(chǔ)的時(shí)候采用Redis當(dāng)中的hash存儲(chǔ)
HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
String userCarKey = USER_CAR_HASH_FIELD_PREFIX + userId;
String jsonStr = opsForHash.get(CAR_KEY, userCarKey);
Map<String,Car> CarMap = JSONObject.parseObject(jsonStr, new TypeReference<Map<String, Car>>() {
});
if (!CarMap.containsKey(bookId)){ //不包含
return;
}
Car car = CarMap.get(bookId);
car.setNumber(number);
//最后將其存入redis當(dāng)中
opsForHash.put(CAR_KEY, userCarKey, JSONObject.toJSONString(CarMap));
stringRedisTemplate.convertAndSend(ChannelEnum.UPDATED.name(), JSONObject.toJSONString(CarMap.get(car.getBookId())));
}
@Override
public void delCar(String[] bookIds, String userId) {
//獲得操作RedisHash的對(duì)象
HashOperations<String, String, String> forHash = stringRedisTemplate.opsForHash();
String userCarKey = USER_CAR_HASH_FIELD_PREFIX+userId;
List<String[]> list = new ArrayList<>();
//從redis中獲取用戶(hù)對(duì)應(yīng)的購(gòu)物車(chē)數(shù)據(jù)
String carJsonStr = forHash.get(CAR_KEY, userCarKey);
//修改指定商品的數(shù)量
Map<String,Car> carMap = JSONObject.parseObject(carJsonStr, new TypeReference<Map<String,Car>>() {
});
for(String bookId : bookIds){
carMap.remove(bookId);
}
//將修改后的數(shù)據(jù)重新添加到redis中
forHash.put(CAR_KEY,userCarKey,JSONObject.toJSONString(carMap));
list.add(bookIds);
list.add(new String[]{userId});
stringRedisTemplate.convertAndSend(ChannelEnum.DELETED.name(), JSONObject.toJSONString(list));
}
}上述的兩段代碼中
第二段代碼中stringRedisTemplate.convertAndSend();就是發(fā)送消息的,其中參數(shù)1是發(fā)送消息的名稱(chēng),參數(shù)2是發(fā)送消息的內(nèi)容
第一段代碼中的這個(gè)就是監(jiān)聽(tīng)到后接收到的消息,其中參數(shù)1{當(dāng)中的onMessage方法的參數(shù)1Message為發(fā)送消息的內(nèi)容,參數(shù)2pattern是發(fā)送消息的名稱(chēng)} 參數(shù)2為監(jiān)聽(tīng)指定的消息名稱(chēng)(這個(gè)要和stringRedisTemplate.convertAndSend()中參數(shù)1的要保持一致)
listenerContainer.addMessageListener(new MessageListener() {
@Override
public void onMessage(Message message, byte[] pattern) {
}
}, new ChannelTopic(ChannelEnum.INSERTED.name()));以上就是使用Java代碼實(shí)現(xiàn)Redis和數(shù)據(jù)庫(kù)數(shù)據(jù)同步的詳細(xì)內(nèi)容,更多關(guān)于Java Redis和數(shù)據(jù)庫(kù)同步的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java 詳細(xì)講解線(xiàn)程安全與同步附實(shí)例與注釋
線(xiàn)程安全是多線(xiàn)程編程時(shí)的計(jì)算機(jī)程序代碼中的一個(gè)概念。在擁有共享數(shù)據(jù)的多條線(xiàn)程并行執(zhí)行的程序中,線(xiàn)程安全的代碼會(huì)通過(guò)同步機(jī)制保證各個(gè)線(xiàn)程都可以正常且正確的執(zhí)行,不會(huì)出現(xiàn)數(shù)據(jù)污染等意外情況2022-04-04
SpringBoot框架整合Mybatis簡(jiǎn)單攻略
這篇文章主要介紹了SpringBoot框架整合Mybatis的簡(jiǎn)單攻略,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-10-10
SpringBoot實(shí)現(xiàn)自定義配置文件提示的方法
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)自定義配置文件提示的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
SpringBoot實(shí)現(xiàn)HTTP調(diào)用的七種方式總結(jié)
小編在工作中,遇到一些需要調(diào)用三方接口的任務(wù),就需要用到 HTTP 調(diào)用工具,這里,我總結(jié)了一下 實(shí)現(xiàn) HTTP 調(diào)用的方式,共有 7 種(后續(xù)會(huì)繼續(xù)新增),需要的朋友可以參考下2023-09-09
Java語(yǔ)言實(shí)現(xiàn)反轉(zhuǎn)鏈表代碼示例
這篇文章主要介紹了Java語(yǔ)言實(shí)現(xiàn)反轉(zhuǎn)鏈表代碼示例,小編覺(jué)得挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-10-10
在RabbitMQ中實(shí)現(xiàn)Work queues工作隊(duì)列模式
這篇文章主要介紹了如何在RabbitMQ中實(shí)現(xiàn)Work queues模式,代碼詳細(xì),解釋清晰,可以幫助大家更好理解java,對(duì)這方面感興趣的朋友可以參考下2021-04-04
Spring?Security實(shí)現(xiàn)接口放通的方法詳解
在用Spring?Security項(xiàng)目開(kāi)發(fā)中,有時(shí)候需要放通某一個(gè)接口時(shí),我們需要在配置中把接口地址配置上,這樣做有時(shí)候顯得麻煩。本文將通過(guò)一個(gè)注解的方式快速實(shí)現(xiàn)接口放通,感興趣的可以了解一下2022-05-05
SpringCloud的網(wǎng)關(guān)Zuul和Gateway詳解
SpringCloudZuul和SpringCloudGateway都是用于構(gòu)建微服務(wù)架構(gòu)中的API網(wǎng)關(guān)的組件,但SpringCloudGateway在性能、功能特性和生態(tài)支持等方面有一些優(yōu)勢(shì),因此推薦使用SpringCloudGateway作為首選2025-02-02

