赞
踩
目录
- @Transactional
- public Map<String,String> addOrder(String cids,Orders order) throws
- SQLException {
- logger.info("add order begin...");
- Map<String, String> map = null;
- //1.校验库存:根据cids查询当前订单中关联的购物⻋记录详情(包括库存)
- String[] arr = cids.split(",");
- List<Integer> cidsList = new ArrayList<>();
- for (int i = 0; i < arr.length; i++) {
- cidsList.add(Integer.parseInt(arr[i]));
- }
-
- //根据⽤户在购物⻋列表中选择的购物⻋记录的id 查询到对应的购物⻋记录
- List<ShoppingCartVO> list =
- shoppingCartMapper.selectShopcartByCids(cidsList);
- //从购物⻋信息中获取到要购买的 skuId(商品ID) 以skuId为key写到redis中: 1
- 2 3
- boolean isLock = true;
- String[] skuIds = new String[list.size()]; //记录已经锁定的商品的ID
- for (int i = 0; i <list.size() ; i++) {
- String skuId = list.get(i).getSkuId(); //订单中可能包含多个商品,
- 每个skuId表示⼀个商品
- Boolean ifAbsent =
- stringRedisTemplate.boundValueOps(skuId).setIfAbsent("fmmall");
- if(ifAbsent){
- skuIds[i] = skuId;
- }
- isLock = isLock && ifAbsent;
- }
- //如果isLock为true,表示“加锁”成功
- if(isLock){
- try{
- //1.⽐较库存: 当第⼀次查询购物⻋记录之后,在加锁成功之前,可能被其他
- 的并发线程修改库存
- List<ShoppingCartVO> list =
- shoppingCartMapper.selectShopcartByCids(cidsList);
- boolean f = true;
- String untitled = "";
- for (ShoppingCartVO sc : list) {
- if (Integer.parseInt(sc.getCartNum()) >
- sc.getSkuStock()) {
- f = false;
- }
- untitled = untitled + sc.getProductName() + ",";
- }
- if (f) {
- //2.添加订单
- //3.保存快照
- //4.修改库存
- //5.删除购物⻋
- map = new HashMap<>();
- logger.info("add order finished...");
- map.put("orderId", orderId);
- map.put("productNames", untitled);
- }
- }catch(Exception e){
- e.printStackTrance();
- }finally{
- //释放锁
- for (int m = 0; m < skuIds.length ; m++) {
- String skuId = skuIds[m];
- if(skuId!=null && !"".equals(skuId)){
- stringRedisTemplate.delete(skuId);
- }
- }
- }
- return map;
- }else{
- //表示加锁失败,订单添加失败
- // 当加锁失败时,有可能对部分商品已经锁定,要释放锁定的部分商品
- for (int i = 0; i < skuIds.length ; i++) {
- String skuId = skuIds[i];
- if(skuId!=null && !"".equals(skuId)){
- stringRedisTemplate.delete(skuId);
- }
- }
- return null;
- }
- }
- if redis.call("get",KEYS[1]) == ARGV[1] then
- return redis.call("del",KEYS[1])
- else
- return 0
- end
- @Bean
- public DefaultRedisScript<List> defaultRedisScript(){
- DefaultRedisScript<List> defaultRedisScript = new
- DefaultRedisScript<>();
- defaultRedisScript.setResultType(List.class);
- defaultRedisScript.setScriptSource(new ResourceScriptSource(new
- ClassPathResource("unlock.lua")));
- return defaultRedisScript; }
- @AutoWired
- private DefaultRedisScript defaultRedisScript;
- //执⾏lua脚本
- List<String> keys = new ArrayList<>();
- keys.add(skuId);
- List rs = stringRedisTemplate.execute(defaultRedisScript,keys ,
- values.get(skuId));
- System.out.println(rs.get(0));
<dependency><groupId> org.redisson </groupId><artifactId> redisson </artifactId><version> 3.12.0 </version></dependency>
redisson :addr :singleAddr :host : redis : //47.96.11.185 : 6370password : 12345678database : 0
- @Configuration
- public class RedissonConfig {
- @Value("${redisson.addr.singleAddr.host}")
- private String host;
- @Value("${redisson.addr.singleAddr.password}")
- private String password;
- @Value("${redisson.addr.singleAddr.database}")
- private int database;
- @Bean
- public RedissonClient redissonClient(){
- Config config = new Config();
-
- config.useSingleServer().setAddress(host).setPassword(password).se
- tDatabase(database);
- return Redisson.create(config);
- }
- }
redisson :addr :singleAddr :host : redis : //47.96.11.185 : 6370password : 12345678database : 0
- @Configuration
- public class RedissonConfig {
- @Value("${redisson.addr.singleAddr.host}")
- private String host;
- @Value("${redisson.addr.singleAddr.password}")
- private String password;
- @Value("${redisson.addr.singleAddr.database}")
- private int database;
- @Bean
- public RedissonClient redissonClient(){
- Config config = new Config();
- config.useSingleServer().setAddress(host).setPassword(password).se
- tDatabase(database);
- return Redisson.create(config);
- }
- }
redisson :addr :cluster :hosts : redis : //47.96.11.185 : 6370,...,redis : //47.96.11.185 : 6373password : 12345678
- @Configuration
- public class RedissonConfig {
- @Value("${redisson.addr.cluster.hosts}")
- private String hosts;
- @Value("${redisson.addr.cluster.password}")
- private String password;
- /**
- * 集群模式
- * @return
- */
- @Bean
- public RedissonClient redissonClient(){
- Config config = new Config();
- config.useClusterServers().addNodeAddress(hosts.split("
- [,]"))
- .setPassword(password)
- .setScanInterval(2000)
- .setMasterConnectionPoolSize(10000)
- .setSlaveConnectionPoolSize(10000);
- return Redisson.create(config);
- }
- }
redisson :addr :masterAndSlave :masterhost : redis : //47.96.11.185 : 6370slavehosts :redis : //47.96.11.185 : 6371,redis : //47.96.11.185 : 6372password : 12345678database : 0
- @Configuration
- public class RedissonConfig3 {
- @Value("${redisson.addr.masterAndSlave.masterhost}")
- private String masterhost;
- @Value("${redisson.addr.masterAndSlave.slavehosts}")
- private String slavehosts;
- @Value("${redisson.addr.masterAndSlave.password}")
- private String password;
- @Value("${redisson.addr.masterAndSlave.database}")
- private int database;
- /**
- * 主从模式
- * @return
- */
- @Bean
- public RedissonClient redissonClient(){
- Config config = new Config();
- config.useMasterSlaveServers()
- .setMasterAddress(masterhost)
- .addSlaveAddress(slavehosts.split("[,]"))
- .setPassword(password)
- .setDatabase(database)
- .setMasterConnectionPoolSize(10000)
- .setSlaveConnectionPoolSize(10000);
- return Redisson.create(config);
- }
- }
// 获取公平锁RLock lock = redissonClient . getFairLock ( skuId );// 获取⾮公平锁RLock lock = redissonClient . getLock ( skuId );
// 阻塞锁(如果加锁成功之后,超时时间为 30s ;加锁成功开启看⻔狗,剩 5s 延⻓过期时间)lock . lock ();// 阻塞锁(如果加锁成功之后,设置⾃定义 20s 的超时时间)lock . lock ( 20 , TimeUnit . SECONDS );// ⾮阻塞锁(设置等待时间为 3s ;如果加锁成功默认超时间为 30s )boolean b = lock . tryLock ( 3 , TimeUnit . SECONDS );// ⾮阻塞锁(设置等待时间为 3s ;如果加锁成功设置⾃定义超时间为 20s )boolean b = lock . tryLock ( 3 , 20 , TimeUnit . SECONDS );
lock . unlock ();
// 公平⾮阻塞锁RLock lock = redissonClient . getFairLock ( skuId );boolean b = lock . tryLock ( 3 , 20 , TimeUnit . SECONDS );
HashMap map = null ;加锁try {if ( isLock ){校验库存if ( 库存充⾜ ){保存订单保存快照修改库存删除购物⻋map = new HashMap ();...}}} catch ( Exception e ){e . printStackTrace ();} finally {释放锁}return map ;
- /**
- * 保存订单业务
- */
- @Transactional
- public Map<String, String> addOrder(String cids, Orders order)
- throws SQLException {
- logger.info("add order begin...");
- Map<String, String> map = null;
- //1.校验库存:根据cids查询当前订单中关联的购物⻋记录详情(包括库存)
- String[] arr = cids.split(",");
- List<Integer> cidsList = new ArrayList<>();
- for (int i = 0; i < arr.length; i++) {
- cidsList.add(Integer.parseInt(arr[i]));
- }
- //根据⽤户在购物⻋列表中选择的购物⻋记录的id 查询到对应的购物⻋记录
- List<ShoppingCartVO> list =
- shoppingCartMapper.selectShopcartByCids(cidsList);
- //加锁
- boolean isLock = true;
- String[] skuIds = new String[list.size()];
- Map<String, RLock> locks = new HashMap<>(); //⽤于存放当前订单的锁
- for (int i = 0; i < list.size(); i++) {
- String skuId = list.get(i).getSkuId();
- boolean b = false;
- try {
- RLock lock = redissonClient.getLock(skuId);
- b = lock.tryLock(10, 3, TimeUnit.SECONDS);
- if (b) {
- skuIds[i] = skuId;
- locks.put(skuId, lock);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- isLock = isLock & b;
- }
- //如果isLock为true,表示“加锁”成功
- try {
- if (isLock){
- //1.检验库存
- boolean f = true;
- String untitled = "";
- list =
- shoppingCartMapper.selectShopcartByCids(cidsList);
- for (ShoppingCartVO sc : list) {
- if (Integer.parseInt(sc.getCartNum()) >
- sc.getSkuStock()) {
- f = false;
- }
- untitled = untitled + sc.getProductName() + ",";
- }
- if (f) {
- //如果库存充⾜,则进⾏下订单操作
- logger.info("product stock is OK...");
- //2.保存订单
- order.setUntitled(untitled);
- order.setCreateTime(new Date());
- order.setStatus("1");
- //⽣成订单编号
- String orderId =
- UUID.randomUUID().toString().replace("-", "");
- order.setOrderId(orderId);
- int i = ordersMapper.insert(order);
- //3.⽣成商品快照
- for (ShoppingCartVO sc : list) {
- int cnum = Integer.parseInt(sc.getCartNum());
- String itemId = System.currentTimeMillis() +
- "" + (new Random().nextInt(89999) + 10000);
- OrderItem orderItem = new OrderItem(itemId,
- orderId, sc.getProductId(), sc.getProductName(),
- sc.getProductImg(), sc.getSkuId(), sc.getSkuName(), new
- BigDecimal(sc.getSellPrice()), cnum, new
- BigDecimal(sc.getSellPrice() * cnum), new Date(), new Date(), 0);
- orderItemMapper.insert(orderItem);
- //增加商品销量
- }
- //4.扣减库存:根据套餐ID修改套餐库存量
- for (ShoppingCartVO sc : list) {
- String skuId = sc.getSkuId();
- int newStock = sc.getSkuStock() -
- Integer.parseInt(sc.getCartNum());
- ProductSku productSku = new ProductSku();
- productSku.setSkuId(skuId);
- productSku.setStock(newStock);
-
- productSkuMapper.updateByPrimaryKeySelective(productSku);
- //5.删除购物⻋:当购物⻋中的记录购买成功之后,购物⻋中对应
- 做删除操作
- for (int cid : cidsList) {
- shoppingCartMapper.deleteByPrimaryKey(cid);
- }
- map = new HashMap<>();
- logger.info("add order finished...");
- map.put("orderId", orderId);
- map.put("productNames", untitled);
- }
- }
- }catch (Exception e){
- e.printStackTrace();
- }finally {
- //释放锁
- for (int i = 0; i < skuIds.length; i++) {
- String skuId = skuIds[i];
- if (skuId != null && !"".equals(skuId)) {
- locks.get(skuId).unlock();
- System.out.println("-----------------------
- unlock");
- }
- }
- }
- return map; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。