preface

The simulation of 20,000 yuan red envelope is divided into 2,000 small red envelopes that can be grabbed, and there are 2,000 people snatching the scene at the same time. The simulation has problems of oversending and how to ensure data consistency.

The project structure

The database table

/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
/* Table: red envelope */
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
create table T_RED_PACKET
(
   id                   int(12)                        not nullAuto_increment COMMENT 'increment COMMENT ', user_idint(12)                        not nullCOMMENT 'id', amountdecimal(16.2)                  not nullCOMMENT 'hongbao amount ', send_date timestamp notnullDEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'CURRENT_TIMESTAMP ', totalint(12)                        not nullCOMMENT 'red amount ', unit_amountdecimal(12)                    not nullCOMMENT 'Single red envelope amount ', Stockint(12)                        not nullCOMMENT 'Remaining number of red packets ', versionint(12) default 0              not nullCOMMENT 'version (for later extension) ', notevarchar(256)                    nullCOMMENT 'COMMENT ',, primary keyclustered (id)
);
Copy the code
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
/* Table: user grab red envelope */
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
create table T_USER_RED_PACKET 
(
   id                   int(12)                        not nullAuto_increment COMMENT 'increment COMMENT id', red_packet_idint(12)                        not nullCOMMENT 'red envelope id', user_idint(12)                        not nullCOMMENT 'id of user ', amountdecimal(16.2)                  not nullGrab_time timestamp not grab_time timestamp notnullDEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'CURRENT_TIMESTAMP ', notevarchar(256)                   nullCOMMENT 'COMMENT ', primary keyclustered (id)
);
Copy the code

Controller

  • RedPacketController
@RestController
@RequestMapping("redPacket")
public class RedPacketController {

    @Resource
    RedPacketService redPacketService;

    @GetMapping("/getRedPacket/{id}")
    public RedPacket getRedPacket(@PathVariable Long id){
        returnredPacketService.getRedPacket(id); }}Copy the code
  • UserRedPacketController
@RestController
@RequestMapping("userRedPacket")
public class UserRedPacketController {


    @Resource
    UserRedPacketService userRedPacketService;

    @GetMapping("/grapRedPacket")
    public FrontResult grapRedPacket(Long redPacketId, Long userId){
        / / a red envelope
        int result = userRedPacketService.grapRedPacket(redPacketId, userId);
        if (result > 0) {return FrontResult.getSuccessResultOnlyMessage("Grab the red envelope successfully");
        }
        return FrontResult.build("1111"."Failed to grab a red envelope!".null); }}Copy the code

Dao

  • RedPacketDao
@Mapper
public interface RedPacketDao {
    /** * get red packet information. *@paramId -- Red envelope ID *@returnRed envelope details */
    RedPacket getRedPacket(Long id);

    /** * Deduct the number of red packets. *@paramId -- Red envelope ID *@returnNumber of updated records */
    int decreaseRedPacket(Long id);
}
Copy the code
  • UserRedPacketDao
@Mapper
public interface UserRedPacketDao {
    /** * Insert the information to grab red packets. *@paramUserRedPacket -- Grab red packet information *@returnNumber of affected records */
    int grapRedPacket(UserRedPacket userRedPacket);
}
Copy the code

pojo

  • FrontResult
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FrontResult implements Serializable {
    /** * Result status code */
    private String code;
    /** * Response result description */
    private String message;
    /** * returns data */
    private Object data;

    /** * static method that returns the front end entity result **@paramCode Status code *@paramMessage message *@paramThe data data *@returnFront-end entity results *@author liuBing
     */
    public static com.xiaogu.pojo.FrontResult build(String code, String message, Object data) {
        return new com.xiaogu.pojo.FrontResult(code, message, data);
    }

    /** * returns a successful result entity **@paramMessage message *@paramThe data data *@returnEntity *@author: liuBing
     * @DATE: 2020/5/25 * /
    public static com.xiaogu.pojo.FrontResult getSuccessResult(String message, Object data) {
        com.xiaogu.pojo.FrontResult result = new com.xiaogu.pojo.FrontResult();
        result.code = ResultCodeEnum.SUCCESS.code;
        result.message = message;
        result.data = data;
        return result;
    }

    /** * returns a success result entity ** without data@paramMessage Message content *@returnReturn result *@author liuBing
     */
    public static com.xiaogu.pojo.FrontResult getSuccessResultOnlyMessage(String message) {
        com.xiaogu.pojo.FrontResult result = new com.xiaogu.pojo.FrontResult();
        result.code = ResultCodeEnum.SUCCESS.code;
        result.message = message;
        result.data = "1";
        return result;
    }

    /** * get an exception result **@paramCode Indicates the error code *@paramMessage User-defined exception message *@return FrontResult
     * @authorLiu * /
    public static com.xiaogu.pojo.FrontResult getExceptionResult(String code, String message) {
        com.xiaogu.pojo.FrontResult result = new com.xiaogu.pojo.FrontResult();
        result.code = code.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.code : code;
        result.message = message.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.getMsg() : message;
        returnresult; }}Copy the code
  • RedPacket
@Data
public class RedPacket implements Serializable {
    private static final long serialVersionUID = 9036484563091364939L;
    // Red envelope number
    private Long id;
    // The user id of the red envelope
    private Long userId;
    // The amount of red envelope
    private Double amount;
    // The date of the red envelope
    private Timestamp sendDate;
    // The total number of red packets
    private Integer total;
    // The amount of a single red envelope
    private Double unitAmount;
    // The number of red packets left
    private Integer stock;
    // Version (for future extensions)
    private Integer version;
    / / note
    private String note;
}
Copy the code
  • UserRedPacket
@Data
@Accessors(chain = true)
public class UserRedPacket implements Serializable {
    private static final long serialVersionUID = 7049215937937620886L;

    // User red envelope ID
    private Long id;
    / / a red envelope id
    private Long redPacketId;
    // The id of the user who grabbed the red envelope
    private Long userId;
    // Grab the red envelope amount
    private Double amount;
    // Grab the red envelope time
    private Timestamp grabTime;
    / / note
    private String note;
}
Copy the code

Service

  • RedPacketService
@Service
public class RedPacketService {

    @Resource
    RedPacketDao redPacketDao;

    /** * get red packets *@paramId Red envelope ID *@returnRed envelope information */
    public RedPacket getRedPacket(Long id) {
        return redPacketDao.getRedPacket(id);
    }

    /** * deduct red envelope *@paramId - no. *@returnAffects the number of entries. */
    public int decreaseRedPacket(Long id){
        returnredPacketDao.decreaseRedPacket(id); }}Copy the code
  • UserRedPacketService
@Service
public class UserRedPacketService {
    @Resource
    UserRedPacketDao userRedPacketDao;

    @Resource
    RedPacketDao redPacketDao;

    public int grapRedPacket(Long redPacketId, Long userId) {
        // Get the red packet information
        RedPacket redPacket = redPacketDao.getRedPacket(redPacketId);
        // Get the red envelope inventory
        int leftRedPacket = redPacket.getStock();
        if (leftRedPacket <= 0) {
            return 0;
        }
        // Update the red envelope inventory
        redPacketDao.decreaseRedPacket(redPacketId);
        System.out.println("Stock quantity remaining:" + leftRedPacket);
        // Generate a message to grab a red envelope
        UserRedPacket userRedPacket = new UserRedPacket();
        userRedPacket.setRedPacketId(redPacketId)
                .setUserId(userId)
                .setAmount(redPacket.getUnitAmount())
                .setNote("redpacket- " + redPacketId);

        returnuserRedPacketDao.grapRedPacket(userRedPacket); }}Copy the code

mapper

  • RedPacketMapper.xml
<! DOCTYPE mapper PUBLIC"- / / mybatis.org//DTD Mapper / 3.0 / EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xiaogu.dao.RedPacketDao"> <! --> <select id="getRedPacket" parameterType="long"
            resultType="com.xiaogu.pojo.RedPacket"> select id, user_id as userId, amount, send_date as sendDate, total, unit_amount as unitAmount, stock, version, note from T_RED_PACKET where id = #{id} </select> <! --> <update id="decreaseRedPacket">
		update T_RED_PACKET set stock = stock - 1 where id =
		#{id}
	</update>


</mapper>
Copy the code
  • UserRedPacketMapper.xml
<? xml version="1.0" encoding="UTF-8"? > <! DOCTYPE mapper PUBLIC"- / / mybatis.org//DTD Mapper / 3.0 / EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xiaogu.dao.UserRedPacketDao"> <! --> <insert id="grapRedPacket" useGeneratedKeys="true"
            keyProperty="id" parameterType="com.xiaogu.pojo.UserRedPacket">
	    insert into
	        T_USER_RED_PACKET
	        ( red_packet_id, user_id, amount, grab_time, note)
	    values
	        (#{redPacketId}, #{userId}, #{amount}, now()#,{note})
    </insert>
</mapper>
Copy the code