package com.example.demo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
public class config extends CachingConfigurerSupport{
private final static Logger logger = LoggerFactory.getLogger(config.class);
@Bean("redisTemplate")
@Primary
public RedisTemplate redisTemplate() {
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);
return redisTemplate;
}
}
秒杀测试代码 1000个线程 抢10个,基本抢不完,还有一次只抢了一个。
package com.example.demo;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisFactApplicationChaoTests {
private final static Logger logger = LoggerFactory.getLogger(RedisFactApplicationChaoTests.class);
@Resource
private RedisTemplate<String,Object> redisTemplate;
private ValueOperations<String,Object> value = null;
long kucun = 0l;
@Before
public void init() throws Exception{
redisTemplate.setEnableTransactionSupport(true);
value = redisTemplate.opsForValue();
value.set("kucun", "10");
kucun = Long.valueOf(value.get("kucun")+"");
logger.info(kucun+"");
}
@After
public void after() throws Exception{
logger.info(value.get("kucun")+"");
}
@Test
public void contextLoads() throws InterruptedException {
for(int i = 0;i<1000 ; i++){
//每个用户件数
Thread t = new Thread(new ExecuteThread(1));
t.start();
latch.countDown();
}
Thread.currentThread().sleep(100000);
}
private CountDownLatch latch = new CountDownLatch(1000);
//总共卖出去多少
private class ExecuteThread implements Runnable {
private int amount;
public ExecuteThread(int amount){
this.amount = amount;
}
public void run() {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
modifyAmount(amount);
}
private void modifyAmount(int count) {
redisTemplate.watch("kucun");
String val = String.valueOf(value.get("kucun"));
int valint = Integer.valueOf(val);
if (valint > 0 && valint - count > 0 ) {
redisTemplate.multi();
value.increment("kucun", -count);
List<Object> list = redisTemplate.exec();
if (list == null || list.size() == 0) {
logger.info("对不起,抢购失败,请重试:"+list.size());
redisTemplate.setEnableDefaultSerializer(false);
}else{
redisTemplate.setEnableDefaultSerializer(false);
logger.info("抢购成功");
}
}
}
}
}
redis乐观锁实现秒杀 缺点:容易抢不完,需要重复抢,redis扣减库存后,程序宕机导致的数据一致性问题。