java中接口异常,redis不回滚
时间: 2024-04-06 11:29:44 浏览: 62
对于Java中接口异常,Redis不会自动回滚事务。这是因为Redis本身并不支持事务的回滚操作,而是采用了一种乐观锁的机制来确保事务的一致性。
在Java中,如果在执行Redis事务的过程中出现了异常,事务中未执行的命令会被自动忽略,而已执行的命令不会回滚。因此,如果需要回滚Redis事务,需要手动执行回滚操作。
一种常见的解决方案是使用Spring框架中的声明式事务管理,它可以将Redis事务和Java事务进行绑定,从而实现在Java事务回滚时自动回滚Redis事务的功能。
相关问题
使用Springboot和mybatis框架开发,给出具体程序,程序包含Dao层,Mapper.xml文件,Service层,Service实现类,Controller层,使用工具类实现抽奖功能1.根据活动查询出相应奖品,并根据奖品概率选出抽中的奖品,记录到抽奖表和中奖表中 2.不在进行中的活动弹出提示 3.超过抽奖限制次数弹出提示 4限制接口频繁访问 10秒内不允许同一个用户访问2次 5抛出异常时事务需要回滚 6.需要校验用户是否存在,奖品是否存在,库存是否足够,否则给与提示
好的,下面是一个简单的示例程序,可能不完全符合您的需求,但可以作为参考:
Dao层:
```java
public interface PrizeDao {
int updateStock(@Param("id") int id, @Param("count") int count);
Prize selectById(@Param("id") int id);
int insertLotteryRecord(LotteryRecord record);
int insertWinningRecord(WinningRecord record);
}
```
Mapper.xml文件:
```xml
<mapper namespace="com.example.demo.dao.PrizeDao">
<update id="updateStock">
update prize set stock = stock - #{count} where id = #{id} and stock >= #{count}
</update>
<select id="selectById" resultType="com.example.demo.entity.Prize">
select * from prize where id = #{id}
</select>
<insert id="insertLotteryRecord" parameterType="com.example.demo.entity.LotteryRecord">
insert into lottery_record (user_id, prize_id, create_time) values (#{userId}, #{prizeId}, now())
</insert>
<insert id="insertWinningRecord" parameterType="com.example.demo.entity.WinningRecord">
insert into winning_record (user_id, prize_id, create_time) values (#{userId}, #{prizeId}, now())
</insert>
</mapper>
```
Service层:
```java
public interface PrizeService {
List<Prize> listPrizesByActivity(int activityId);
Prize draw(int userId, int activityId) throws BusinessException;
}
```
Service实现类:
```java
@Service
public class PrizeServiceImpl implements PrizeService {
@Autowired
private PrizeDao prizeDao;
@Autowired
private RedisTemplate<String, Integer> redisTemplate;
@Override
public List<Prize> listPrizesByActivity(int activityId) {
// TODO 查询活动对应的奖品列表
return null;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Prize draw(int userId, int activityId) throws BusinessException {
// 检查活动是否进行中
// TODO
// 检查用户是否存在
// TODO
// 检查用户是否已经抽过奖
String key = "draw:" + userId + ":" + activityId;
Boolean exists = redisTemplate.hasKey(key);
if (exists != null && exists) {
throw new BusinessException("您已经抽过奖了");
}
// 检查用户是否超过抽奖次数限制
int limit = 3;
Integer count = redisTemplate.opsForValue().get(key);
if (count != null && count >= limit) {
throw new BusinessException("您已经超过抽奖次数限制");
}
// 检查并更新奖品库存
List<Prize> prizes = listPrizesByActivity(activityId);
Prize prize = null;
for (Prize p : prizes) {
int stock = p.getStock();
if (stock > 0) {
prize = p;
int rows = prizeDao.updateStock(p.getId(), 1);
if (rows > 0) {
break;
}
}
}
if (prize == null) {
throw new BusinessException("奖品已经全部抽完了");
}
// 记录抽奖记录和中奖记录
LotteryRecord lotteryRecord = new LotteryRecord();
lotteryRecord.setUserId(userId);
lotteryRecord.setPrizeId(prize.getId());
prizeDao.insertLotteryRecord(lotteryRecord);
WinningRecord winningRecord = new WinningRecord();
winningRecord.setUserId(userId);
winningRecord.setPrizeId(prize.getId());
prizeDao.insertWinningRecord(winningRecord);
// 更新抽奖次数限制
if (count == null) {
redisTemplate.opsForValue().set(key, 1, 10, TimeUnit.SECONDS);
} else {
redisTemplate.opsForValue().increment(key, 1);
}
return prize;
}
}
```
Controller层:
```java
@RestController
@RequestMapping("/prize")
public class PrizeController {
@Autowired
private PrizeService prizeService;
@GetMapping("/draw")
public Prize draw(@RequestParam int userId, @RequestParam int activityId) throws BusinessException {
return prizeService.draw(userId, activityId);
}
}
```
工具类:
```java
@Component
public class RedisUtils {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public boolean isFrequentAccess(String key, Duration duration, int limit) {
String countKey = "freq:" + key;
Long count = redisTemplate.opsForValue().increment(countKey, 1);
if (count == 1) {
redisTemplate.expire(countKey, duration);
}
return count != null && count > limit;
}
}
```
抽奖接口的实现中,需要调用Dao层的方法更新奖品库存、记录抽奖记录和中奖记录。同时,需要实现限制抽奖次数、限制接口频繁访问等功能。抽奖次数限制和接口频繁访问限制可以使用Redis实现。在抽奖过程中,如果出现异常,需要进行事务回滚。
阅读全文