秒殺服務實戰

針對mysql和mongo的兩個小例子:java

 

mysql:mysql

import com.example.demo.mapper.OrderInfoMapper;
import com.example.demo.mapper.ProductInfoMapper;
import com.example.demo.model.OrderInfo;
import com.example.demo.model.ProductInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class OrderMysqlService {
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private ProductInfoMapper productInfoMapper;

    //下單
    public boolean insert(){
        Long productId = 22l;//產品id
        int buyCount = 1;//當前用戶下單數量

        if(updateProductAmount(productId,buyCount)){
//            if(true){
//                throw new RuntimeException();
//            }
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setStatus(1);
            orderInfo.setCreateTime(new Date());
            return orderInfoMapper.insertSelective(orderInfo) > 0;
        }
        return false;
    }

    //秒殺服務,修改庫存
    private boolean updateProductAmount(Long productId,int buyCount) {
        ProductInfo productInfo = productInfoMapper.selectByPrimaryKeyByBuyCount(productId,buyCount);
        if (productInfo == null) {
            return false;
        }

        if (productInfoMapper.updateByStock(productId, buyCount) > 0) {
            return true;
        }

        //若是更新失敗,當前線程休眠,錯峯執行(同時執行的話,仍是隻有一我的搶佔到資源,別的都失敗,因此錯峯執行)
        waitForLock();
        return updateProductAmount(productId, buyCount);
    }

    private void waitForLock(){
        try {
            TimeUnit.MILLISECONDS.sleep(new Random().nextInt(10) + 1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

 

mongo:副本集mongodb才能支持事物:4.0以後的版本才能支持事物
            4.0支持事物的步驟搭建:https://blog.csdn.net/quanmaoluo5461/article/details/84880850
git

import com.example.demo.model.Order;
import com.example.demo.model.Product;
import com.mongodb.client.result.UpdateResult;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class OrderMongoService {
    @Autowired
    private MongoTemplate mongoTemplate;

    //下單 : 副本集mongodb才能支持事物。意思就是至少兩個mongo服務。具體操做查看:https://blog.csdn.net/quanmaoluo5461/article/details/84880850
    @Transactional
    public boolean insert(){
        String productId = "5c23a6b4be592e584c8d7c47";//產品id
        int buyCount = 1;//當前用戶下單數量

        if(updateProductAmount(productId,buyCount)){
//            if(true){
//                throw new RuntimeException();
//            }
            Order order = new Order();
            order.setStatus(1);
            return mongoTemplate.insert(order).getId() != null;
        }
        return false;
    }

    //秒殺服務,修改庫存
    private boolean updateProductAmount(String productId,int buyCount) {
        Criteria criteria = Criteria.where("id").is(new ObjectId(productId))
                .and("stock").gte(buyCount);
        Query query = new Query(criteria);
        Product product = mongoTemplate.findOne(query,Product.class);
        if (product == null) {
            return false;
        }

        Update update = new Update();
        update.inc("stock", -buyCount);
        UpdateResult updateResult= mongoTemplate.updateFirst(query, update, Product.class);
        if(updateResult.getModifiedCount() > 0){
            return true;
        }

        //若是更新失敗,當前線程休眠,錯峯執行(同時執行的話,仍是隻有一我的搶佔到資源,別的都失敗,因此錯峯執行)
        waitForLock();
        return updateProductAmount(productId, buyCount);
    }

    private void waitForLock(){
        try {
            TimeUnit.MILLISECONDS.sleep(new Random().nextInt(10) + 1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

源碼地址:https://github.com/qjm201000/seckill.gitgithub

說明:mysql的sql文件(concurrent.sql)放在項目跟目錄下;mongodb的數據庫文件純json字符串,未備份,數據結構和mysql同樣。spring

相關文章
相關標籤/搜索