码友<马丁的早晨>的建议 使用AOP + 锁实现

This commit is contained in:
小柒2012
2018-05-21 13:29:20 +08:00
parent 6e4bb09dca
commit 0309412d60
6 changed files with 139 additions and 29 deletions

View File

@@ -0,0 +1,40 @@
package com.itstyle.seckill.common.aop;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* 同步锁 AOP
* 创建者 张志朋
* 创建时间 2015年6月3日
*/
@Component
@Scope
@Aspect
public class LockAspect {
/**
* 思考为什么不用synchronized
* service 默认是单例的并发下lock只有一个实例
*/
private static Lock lock = new ReentrantLock(true);//互斥锁 参数默认false不公平锁
//Service层切点 用于记录错误日志
@Pointcut("@annotation(com.itstyle.seckill.common.aop.Servicelock)")
public void lockAspect() {
}
@Around("lockAspect()")
public Object doAfterThrowing(ProceedingJoinPoint joinPoint) throws Throwable {
lock.lock();
Object obj= joinPoint.proceed();
lock.unlock();
return obj;
}
}

View File

@@ -0,0 +1,13 @@
package com.itstyle.seckill.common.aop;
import java.lang.annotation.*;
/**
* 自定义注解 同步锁
* 创建者 张志朋
* 创建时间 2015年6月3日
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Servicelock {
String description() default "";
}

View File

@@ -47,6 +47,13 @@ public interface ISeckillService {
* @return
*/
Result startSeckilLock(long seckillId,long userId);
/**
* 秒杀 二、程序锁AOP
* @param seckillId
* @param userId
* @return
*/
Result startSeckilAopLock(long seckillId,long userId);
/**
* 秒杀 二、数据库悲观锁

View File

@@ -10,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.itstyle.seckill.common.aop.Servicelock;
import com.itstyle.seckill.common.dynamicquery.DynamicQuery;
import com.itstyle.seckill.common.entity.Result;
import com.itstyle.seckill.common.entity.Seckill;
@@ -110,6 +111,28 @@ public class SeckillServiceImpl implements ISeckillService {
return Result.ok(SeckillStatEnum.SUCCESS);
}
@Override
@Servicelock
@Transactional
public Result startSeckilAopLock(long seckillId, long userId) {
//来自码云码友<马丁的早晨>的建议 使用AOP + 锁实现
String nativeSql = "SELECT number FROM seckill WHERE seckill_id=?";
Object object = dynamicQuery.nativeQueryObject(nativeSql, new Object[]{seckillId});
Long number = ((Number) object).longValue();
if(number>0){
nativeSql = "UPDATE seckill SET number=number-1 WHERE seckill_id=?";
dynamicQuery.nativeExecuteUpdate(nativeSql, new Object[]{seckillId});
SuccessKilled killed = new SuccessKilled();
killed.setSeckillId(seckillId);
killed.setUserId(userId);
killed.setState(Short.parseShort(number+""));
killed.setCreateTime(new Timestamp(new Date().getTime()));
dynamicQuery.save(killed);
}else{
return Result.error(SeckillStatEnum.END);
}
return Result.ok(SeckillStatEnum.SUCCESS);
}
@Override
@Transactional
public Result startSeckilDBPCC_ONE(long seckillId, long userId) {
//单用户抢购一件商品或者多件都没有问题
@@ -173,4 +196,5 @@ public class SeckillServiceImpl implements ISeckillService {
return Result.error(SeckillStatEnum.END);
}
}
}

View File

@@ -84,12 +84,38 @@ public class SeckillController {
}
return Result.ok();
}
@ApiOperation(value="秒杀三(数据库悲观锁)",nickname="科帮网")
@ApiOperation(value="秒杀三(AOP程序锁)",nickname="科帮网")
@PostMapping("/startLock")
public Result startAopLock(long seckillId){
seckillService.deleteSeckill(seckillId);
final long killId = seckillId;
LOGGER.info("开始秒杀三(正常)");
for(int i=0;i<1000;i++){
final long userId = i;
Runnable task = new Runnable() {
@Override
public void run() {
Result result = seckillService.startSeckilLock(killId, userId);
LOGGER.info("用户:{}{}",userId,result.get("msg"));
}
};
executor.execute(task);
}
try {
Thread.sleep(10000);
Long seckillCount = seckillService.getSeckillCount(seckillId);
LOGGER.info("一共秒杀出{}件商品",seckillCount);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Result.ok();
}
@ApiOperation(value="秒杀四(数据库悲观锁)",nickname="科帮网")
@PostMapping("/startDBPCC_ONE")
public Result startDBPCC_ONE(long seckillId){
seckillService.deleteSeckill(seckillId);
final long killId = seckillId;
LOGGER.info("开始秒杀(正常)");
LOGGER.info("开始秒杀(正常)");
for(int i=0;i<1000;i++){
final long userId = i;
Runnable task = new Runnable() {
@@ -110,12 +136,12 @@ public class SeckillController {
}
return Result.ok();
}
@ApiOperation(value="秒杀(数据库悲观锁)",nickname="科帮网")
@ApiOperation(value="秒杀(数据库悲观锁)",nickname="科帮网")
@PostMapping("/startDPCC_TWO")
public Result startDPCC_TWO(long seckillId){
seckillService.deleteSeckill(seckillId);
final long killId = seckillId;
LOGGER.info("开始秒杀(正常、数据库锁最优实现)");
LOGGER.info("开始秒杀(正常、数据库锁最优实现)");
for(int i=0;i<1000;i++){
final long userId = i;
Runnable task = new Runnable() {
@@ -136,12 +162,12 @@ public class SeckillController {
}
return Result.ok();
}
@ApiOperation(value="秒杀(数据库乐观锁)",nickname="科帮网")
@ApiOperation(value="秒杀(数据库乐观锁)",nickname="科帮网")
@PostMapping("/startDBOCC")
public Result startDBOCC(long seckillId){
seckillService.deleteSeckill(seckillId);
final long killId = seckillId;
LOGGER.info("开始秒杀(正常、数据库锁最优实现)");
LOGGER.info("开始秒杀(正常、数据库锁最优实现)");
for(int i=0;i<1000;i++){
final long userId = i;
Runnable task = new Runnable() {
@@ -162,12 +188,12 @@ public class SeckillController {
}
return Result.ok();
}
@ApiOperation(value="秒杀(进程内队列)",nickname="科帮网")
@ApiOperation(value="秒杀(进程内队列)",nickname="科帮网")
@PostMapping("/startQueue")
public Result startQueue(long seckillId){
seckillService.deleteSeckill(seckillId);
final long killId = seckillId;
LOGGER.info("开始秒杀(正常)");
LOGGER.info("开始秒杀(正常)");
for(int i=0;i<1000;i++){
final long userId = i;
Runnable task = new Runnable() {