JAva同時プログラミング学習21--springbootに基づく秒殺システム実現3-ストレージプロセス


【ストレージ・プロシージャとは
ストアド・プロシージャとは、特定の機能を果たすためのSQL文セットのグループで、コンパイルされてデータベースに格納され、ユーザーはストアド・プロシージャの名前を指定し、パラメータ(このストアド・プロシージャにパラメータがある場合)を指定することによって実行を呼び出す.制御文で記述することができ、柔軟性が高く、複雑な判断と複雑な演算を完了することができる.
【ストレージ・プロシージャの使用理由
現在の状況では、update操作があるため、トランザクションを使用して操作の原子性を保証する必要がありますが、現在のトランザクションの制御はspringに渡されて制御されているため、真ん中にネットワーク遅延があり、GCの時間がかかります(GC時にはすべてのスレッドが掛かり、同時数が高いほどGCが頻繁になります).updateのレコードは行レベルロックによって制御され、すべての操作はシリアルしかできないため、大量にブロックされ、ユーザー体験に影響を与えます.
しかし、MySQL自体をテストしたupdateは40000回/秒で、かなり良いデータなので、ここではトランザクションをMySQLに直接渡し、ストレージ・プロシージャを使用して行レベルのロックの保有時間を低減します.
【ストアド・プロシージャ・コード
ストレージ・プロシージャを使用する前に、データベースがストレージ・プロシージャを作成していることを確認する必要があります.DELIMITERは、';'の代わりに'$'を使用してストレージ中に使用することを示します.最後にDELIMITERが必要です.元に戻す.ここのout r_resultは出力を表しますが、ここでの出力はプロジェクトのKillStatus列挙値に対応し、秒殺の結果を示す必要があります.
DELIMITER $$
CREATE PROCEDURE `seckill`.`execute_seckill`
    (in v_id VARCHAR(36),in v_kill_product_id VARCHAR(36),in v_mobile BIGINT,in v_kill_time TIMESTAMP,out r_result int)
    BEGIN
        DECLARE insert_count int DEFAULT 0;
    START TRANSACTION;
    INSERT IGNORE INTO kill_item(id,kill_product_id,mobile) values(v_id,v_kill_product_id,v_mobile);
    SELECT ROW_COUNT() INTO insert_count;
        IF(insert_count = 0) THEN
            ROLLBACK;
            SET r_result = -1;
        ELSEIF(insert_count < 0) THEN
            ROLLBACK;
            SET r_result = -2;
        ELSE
            UPDATE kill_product SET number = number - 1
            WHERE id = v_kill_product_id AND number >= 1 AND end_time > v_kill_time AND start_time < v_kill_time;
            SELECT ROW_COUNT() INTO insert_count;
            IF(insert_count = 0) THEN
                ROLLBACK;
                SET r_result = 0;
            ELSEIF(insert_count < 0) THEN
                ROLLBACK;
                SET r_result = -2;
            ELSE
                COMMIT;
                SET r_result = 1;
            END IF;
        END IF;
    END;
$$
DELIMITER ;

【springdataJPAでストレージ・プロシージャを呼び出す
Entityには、springというEntityが適切なストレージ・プロシージャを持っていることを示す注釈が必要です.
import lombok.Data;

import javax.persistence.*;
import java.util.Date;

/**
 *        
 * @author ibm
 * @since 0
 * @date 2018/3/22
 */
@Entity
@Table(name = "kill_item")
@NamedStoredProcedureQuery(name = "executeSeckill", procedureName = "execute_seckill", parameters = {
        @StoredProcedureParameter(mode = ParameterMode.IN, name = "v_id", type = String.class),
        @StoredProcedureParameter(mode = ParameterMode.IN, name = "v_kill_product_id", type = String.class),
        @StoredProcedureParameter(mode = ParameterMode.IN, name = "v_mobile", type = Long.class),
        @StoredProcedureParameter(mode = ParameterMode.IN, name = "v_kill_time", type = Date.class),
        @StoredProcedureParameter(mode = ParameterMode.OUT, name = "r_result", type = Integer.class) })
@Data
public class KillItem {

    /**
     *   ID
     */
    @Id
    @Column(name = "id")
    private String id;
    /**
     *     id
     */
    @Column(name = "kill_product_id")
    private String killProductId;
    /**
     *       
     */
    @Column(name = "mobile")
    private String mobile;
    /**
     *       
     */
    @Column(name = "kill_time")
    private Date killTime;
}

対応するRepositoryでは、どのストレージ・プロシージャを呼び出す必要があるかをメソッド(executeProcedure)に伝える必要があります.このメソッドの戻り値はストレージ・プロシージャのoutであり、パラメータはストレージ・プロシージャのinであることに注意してください.
import com.example.seckill.dao.entity.KillItem;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.repository.query.Param;

import java.util.Date;
import java.util.List;

/**
 * @author ibm
 * @since 0
 * @date 2018/3/22
 */
public interface KillItemJpaRepo extends JpaRepository {

    /**
     *            
     * @param killProductId     Id
     * @return       
     */
    List findAllByKillProductIdOrderByKillTimeDesc(String killProductId);

    /**
     *       
     * @param id       
     * @param killProductId     id
     * @param mobile          
     * @return      
     */
    @Modifying
    @Query(value = "INSERT IGNORE INTO kill_item(id,kill_product_id,mobile) values(?1,?2,?3)",
            nativeQuery = true)
    int insertKillItem(String id,String killProductId,long mobile);


    @Procedure(procedureName = "execute_seckill")
    int executeProcedure(@Param("v_id")String killItemId,
                         @Param("v_kill_product_id")String killProductId,
                         @Param("v_mobile")long mobile,
                         @Param("v_kill_time")Date killTime);
}

【まとめ
これですべての最適化が完了しました.
       1.       -> CDN     (css,js)
                            1.           
                            2.             
                            3.CDN          

        2.         ->     CDN,             
                            1.       :redis
                            2.       MySQL

        3.         ->     CDN,                  ,       。
                            1.          
                            2.        MySQL     
                            3.      ,     MySQL  
        
        4.     ->     ,        

【事業所住所
プロジェクトの原型は慕課網に由来する.https://www.imooc.com/learn/632SpringBootベースのバージョン:https://github.com/jipingongz...