Skip to content

Commit 8f7a3bb

Browse files
committed
添加redis解决暴露秒杀地址时的高并发
1 parent 5680fdc commit 8f7a3bb

File tree

4 files changed

+141
-18
lines changed

4 files changed

+141
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,71 @@
11
package cn.codingxiaxw.dao.cache;
22

3+
import cn.codingxiaxw.entity.Seckill;
4+
import com.dyuproject.protostuff.LinkedBuffer;
5+
import com.dyuproject.protostuff.ProtostuffIOUtil;
6+
import com.dyuproject.protostuff.runtime.RuntimeSchema;
7+
import redis.clients.jedis.Jedis;
8+
import redis.clients.jedis.JedisPool;
9+
310
/**
411
* Created by codingBoy on 17/2/17.
512
*/
613
public class RedisDao {
14+
private final JedisPool jedisPool;
15+
16+
public RedisDao(String ip, int port) {
17+
jedisPool = new JedisPool(ip, port);
18+
}
19+
20+
private RuntimeSchema<Seckill> schema = RuntimeSchema.createFrom(Seckill.class);
21+
22+
23+
public Seckill getSeckill(long seckillId) {
24+
//redis操作逻辑
25+
try {
26+
Jedis jedis = jedisPool.getResource();
27+
try {
28+
String key = "seckill:" + seckillId;
29+
//并没有实现哪部序列化操作
30+
//采用自定义序列化
31+
//protostuff: pojo.
32+
byte[] bytes = jedis.get(key.getBytes());
33+
//缓存重获取到
34+
if (bytes != null) {
35+
Seckill seckill=schema.newMessage();
36+
ProtostuffIOUtil.mergeFrom(bytes,seckill,schema);
37+
//seckill被反序列化
38+
39+
return seckill;
40+
}
41+
}finally {
42+
jedis.close();
43+
}
44+
}catch (Exception e) {
45+
46+
}
47+
return null;
48+
}
49+
50+
public String putSeckill(Seckill seckill) {
51+
try {
52+
Jedis jedis = jedisPool.getResource();
53+
try {
54+
String key = "seckill:" + seckill.getSeckillId();
55+
byte[] bytes = ProtostuffIOUtil.toByteArray(seckill, schema,
56+
LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
57+
//超时缓存
58+
int timeout = 60 * 60;//1小时
59+
String result = jedis.setex(key.getBytes(),timeout,bytes);
60+
61+
return result;
62+
}finally {
63+
jedis.close();
64+
}
65+
}catch (Exception e) {
66+
67+
}
68+
69+
return null;
70+
}
771
}

src/main/java/cn/codingxiaxw/service/impl/SeckillServiceImpl.java

+35-15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import cn.codingxiaxw.dao.SeckillDao;
44
import cn.codingxiaxw.dao.SuccessKilledDao;
5+
import cn.codingxiaxw.dao.cache.RedisDao;
56
import cn.codingxiaxw.dto.Exposer;
67
import cn.codingxiaxw.dto.SeckillExecution;
78
import cn.codingxiaxw.entity.Seckill;
@@ -42,6 +43,9 @@ public class SeckillServiceImpl implements SeckillService
4243
@Autowired //@Resource
4344
private SuccessKilledDao successKilledDao;
4445

46+
@Autowired
47+
private RedisDao redisDao;
48+
4549
public List<Seckill> getSeckillList() {
4650
return seckillDao.queryAll(0,4);
4751
}
@@ -51,12 +55,24 @@ public Seckill getById(long seckillId) {
5155
}
5256

5357
public Exposer exportSeckillUrl(long seckillId) {
54-
Seckill seckill=seckillDao.queryById(seckillId);
55-
if (seckill==null) //说明查不到这个秒杀产品的记录
56-
{
57-
return new Exposer(false,seckillId);
58+
//优化点:缓存优化:超时的基础上维护一致性
59+
//1。访问redi
60+
61+
62+
Seckill seckill = redisDao.getSeckill(seckillId);
63+
if (seckill == null) {
64+
//2.访问数据库
65+
seckill = seckillDao.queryById(seckillId);
66+
if (seckill == null) {//说明查不到这个秒杀产品的记录
67+
return new Exposer(false, seckillId);
68+
}else {
69+
//3,放入redis
70+
redisDao.putSeckill(seckill);
71+
}
72+
5873
}
5974

75+
6076
//若是秒杀未开启
6177
Date startTime=seckill.getStartTime();
6278
Date endTime=seckill.getEndTime();
@@ -98,26 +114,30 @@ public SeckillExecution executeSeckill(long seckillId, long userPhone, String md
98114
Date nowTime=new Date();
99115

100116
try{
101-
//减库存
102-
int updateCount=seckillDao.reduceNumber(seckillId,nowTime);
103-
if (updateCount<=0)
117+
118+
//否则更新了库存,秒杀成功,增加明细
119+
int insertCount=successKilledDao.insertSuccessKilled(seckillId,userPhone);
120+
//看是否该明细被重复插入,即用户是否重复秒杀
121+
if (insertCount<=0)
104122
{
105-
//没有更新库存记录,说明秒杀结束
106-
throw new SeckillCloseException("seckill is closed");
123+
throw new RepeatKillException("seckill repeated");
107124
}else {
108-
//否则更新了库存,秒杀成功,增加明细
109-
int insertCount=successKilledDao.insertSuccessKilled(seckillId,userPhone);
110-
//看是否该明细被重复插入,即用户是否重复秒杀
111-
if (insertCount<=0)
125+
126+
//减库存,热点商品竞争
127+
int updateCount=seckillDao.reduceNumber(seckillId,nowTime);
128+
if (updateCount<=0)
112129
{
113-
throw new RepeatKillException("seckill repeated");
130+
//没有更新库存记录,说明秒杀结束 rollback
131+
throw new SeckillCloseException("seckill is closed");
114132
}else {
115-
//秒杀成功,得到成功插入的明细记录,并返回成功秒杀的信息
133+
//秒杀成功,得到成功插入的明细记录,并返回成功秒杀的信息 commit
116134
SuccessKilled successKilled=successKilledDao.queryByIdWithSeckill(seckillId,userPhone);
117135
return new SeckillExecution(seckillId, SeckillStatEnum.SUCCESS,successKilled);
118136
}
137+
119138
}
120139

140+
121141
}catch (SeckillCloseException e1)
122142
{
123143
throw e1;

src/main/resources/spring/spring-dao.xml

+5-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@
5454
<property name="basePackage" value="cn.codingxiaxw.dao"/>
5555
</bean>
5656

57-
58-
59-
57+
<!--redisDao-->
58+
<bean id="redisDao" class="cn.codingxiaxw.dao.cache.RedisDao">
59+
<constructor-arg index="0" value="localhost"/>
60+
<constructor-arg index="1" value="6379"/>
61+
</bean>
6062
</beans>
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,45 @@
1+
package cn.codingxiaxw.dao.cache;
2+
3+
import cn.codingxiaxw.dao.SeckillDao;
4+
import cn.codingxiaxw.entity.Seckill;
5+
import org.junit.Test;
6+
import org.junit.runner.RunWith;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.test.context.ContextConfiguration;
9+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
10+
111
import static org.junit.Assert.*;
212

313
/**
414
* Created by codingBoy on 17/2/17.
515
*/
16+
@RunWith(SpringJUnit4ClassRunner.class)
17+
//告诉junit spring的配置文件
18+
@ContextConfiguration({"classpath:spring/spring-dao.xml"})
619
public class RedisDaoTest {
720

21+
private long id = 1001;
22+
23+
@Autowired
24+
private RedisDao redisDao;
25+
26+
@Autowired
27+
private SeckillDao seckillDao;
28+
29+
@Test
30+
public void testSeckill() throws Exception {
31+
//get and put
32+
33+
Seckill seckill = redisDao.getSeckill(id);
34+
if (seckill == null) {
35+
seckill = seckillDao.queryById(id);
36+
if (seckill != null) {
37+
String result = redisDao.putSeckill(seckill);
38+
System.out.println(result);
39+
seckill = redisDao.getSeckill(id);
40+
System.out.println(seckill);
41+
}
42+
}
43+
}
44+
845
}

0 commit comments

Comments
 (0)