Browse Source

并发优化

lh_vote_java
lenghui 5 months ago
parent
commit
4c9149ff8e
  1. 3
      src/main/java/com/lh/controller/VoteController.java
  2. 35
      src/main/java/com/lh/service/VoteConsumer.java
  3. 31
      src/main/java/com/lh/service/VoteServiceImpl.java

3
src/main/java/com/lh/controller/VoteController.java

@ -2,7 +2,6 @@ package com.lh.controller;
import com.lh.bean.RespBean; import com.lh.bean.RespBean;
import com.lh.bean.Voter; import com.lh.bean.Voter;
import com.lh.service.VoteConsumer;
import com.lh.service.VoteService; import com.lh.service.VoteService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -13,8 +12,6 @@ import org.springframework.web.bind.annotation.*;
public class VoteController { public class VoteController {
@Autowired @Autowired
private VoteService voteService; private VoteService voteService;
@Autowired
private VoteConsumer voteConsumer;
//投票 //投票
@PostMapping("/vote") @PostMapping("/vote")
public RespBean vote(@RequestBody Voter voter) throws Exception { public RespBean vote(@RequestBody Voter voter) throws Exception {

35
src/main/java/com/lh/service/VoteConsumer.java

@ -1,7 +1,6 @@
package com.lh.service; package com.lh.service;
import com.lh.bean.Candidate; import com.lh.bean.Candidate;
import com.lh.bean.Voter;
import com.lh.exception.MyException; import com.lh.exception.MyException;
import com.lh.mapper.CandidatesMapper; import com.lh.mapper.CandidatesMapper;
import com.lh.mapper.VoterMapper; import com.lh.mapper.VoterMapper;
@ -12,11 +11,6 @@ import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service @Service
@EnableKafka @EnableKafka
public class VoteConsumer { public class VoteConsumer {
@ -52,13 +46,17 @@ public class VoteConsumer {
} }
// 3. 检查用户是否已经为该候选人投过票 // 3. 检查用户是否已经为该候选人投过票
List<Voter> hasVotes = voterMapper.countVotesToday(voterJwcode);
//遍历列表判断是否有记录
for (Voter vote : hasVotes) {
if (vote.getCandidateJwCode().equals(candidateJwcode)) {
throw new MyException("已投票,可以选择其他人试试哦~");
}
}
//List<Voter> hasVotes = voterMapper.countVotesToday(voterJwcode);
////遍历列表判断是否有记录
//boolean flag = true;
//for (Voter vote : hasVotes) {
// if (vote.getCandidateJwCode().equals(candidateJwcode)) {
// flag = false;
// }
//}
//if (!flag){
// throw new MyException("已投票,可以选择其他人试试哦~");
//}
// 4. 增加候选人票数 // 4. 增加候选人票数
if (!candidatesMapper.addVotes(candidateJwcode)) { if (!candidatesMapper.addVotes(candidateJwcode)) {
@ -68,16 +66,7 @@ public class VoteConsumer {
// 5. 插入投票记录 // 5. 插入投票记录
voterMapper.insertVote(voterJwcode, candidateJwcode, voterName); voterMapper.insertVote(voterJwcode, candidateJwcode, voterName);
// 6. 更新 Redis 中的投票次数
String redisKey = "vote_count:" + voterJwcode + ":" + LocalDateTime.now().toLocalDate();
redisTemplate.opsForValue().increment(redisKey, 1);
// 设置 Redis 键的过期时间为当天的23:59:59
LocalDateTime now = LocalDateTime.now();
LocalDateTime endOfDay = now.toLocalDate().atTime(23, 59, 59);
long secondsUntilEndOfDay = Duration.between(now, endOfDay).getSeconds();
redisTemplate.expire(redisKey, secondsUntilEndOfDay, TimeUnit.SECONDS);
//打印剩余长时间过期
System.out.println("Redis键" + redisKey + "将在" + secondsUntilEndOfDay + "秒后过期。");
System.out.println("投票成功!用户:" + voterJwcode + " 投给了 " + candidateJwcode); System.out.println("投票成功!用户:" + voterJwcode + " 投给了 " + candidateJwcode);
return true; return true;
} }

31
src/main/java/com/lh/service/VoteServiceImpl.java

@ -16,10 +16,12 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
@Service @Service
public class VoteServiceImpl implements VoteService { public class VoteServiceImpl implements VoteService {
@ -60,8 +62,35 @@ public class VoteServiceImpl implements VoteService {
throw new MyException("今日投票次数已达上限"); throw new MyException("今日投票次数已达上限");
} }
//将redis中的candidates中的投票次数+1
// 2. 检查该用户是否已经为该候选人投票
String voteStatusKey = "vote_status:" + voterJwcode + ":" + candidateJwcode;
Boolean hasVoted = stringRedisTemplate.hasKey(voteStatusKey);
if (hasVoted != null && hasVoted) {
throw new MyException("您已经为该候选人投票,不能重复投票");
}
// 2. 增加候选人的投票数Hash 表和 ZSet 同步更新
String candidateKey = "candidate:" + candidateJwcode;
// 使用 Redis Hash 增加候选人投票数
redisTemplate.opsForHash().increment(candidateKey, "votes", 1);
// 使用 Redis ZSet 增加候选人投票数
redisTemplate.opsForZSet().incrementScore("candidate:votes", candidateJwcode, 1);
// 6. 更新 Redis 中的投票次数
redisTemplate.opsForValue().increment(redisKey, 1);
// 设置 Redis 键的过期时间为当天的23:59:59
LocalDateTime now = LocalDateTime.now();
LocalDateTime endOfDay = now.toLocalDate().atTime(23, 59, 59);
long secondsUntilEndOfDay = Duration.between(now, endOfDay).getSeconds();
redisTemplate.expire(redisKey, secondsUntilEndOfDay, TimeUnit.SECONDS);
//更新投票重复键
stringRedisTemplate.opsForValue().set(voteStatusKey, "true", secondsUntilEndOfDay, TimeUnit.SECONDS);
//打印剩余长时间过期
System.out.println("Redis键" + redisKey + "将在" + secondsUntilEndOfDay + "秒后过期。");
System.out.println("Redis键" + voteStatusKey + "将在" + secondsUntilEndOfDay + "秒后过期。");
//将投票请求发送到 Kafka 消息队列 //将投票请求发送到 Kafka 消息队列
voteProducer.sendVoteMessage(new VoteMessage(voterJwcode, voteProducer.sendVoteMessage(new VoteMessage(voterJwcode,

Loading…
Cancel
Save