├── .idea ├── compiler.xml ├── encodings.xml ├── inspectionProfiles │ └── Project_Default.xml ├── libraries │ ├── Maven__ch_qos_logback_logback_classic_1_1_7.xml │ ├── Maven__ch_qos_logback_logback_core_1_1_7.xml │ ├── Maven__com_alibaba_druid_1_0_18.xml │ ├── Maven__com_alibaba_fastjson_1_2_31.xml │ ├── Maven__com_fasterxml_classmate_1_3_1.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_annotations_2_8_3.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_core_2_8_3.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_databind_2_8_3.xml │ ├── Maven__com_jayway_jsonpath_json_path_2_2_0.xml │ ├── Maven__com_rabbitmq_amqp_client_3_6_3.xml │ ├── Maven__com_rabbitmq_http_client_1_0_0_RELEASE.xml │ ├── Maven__commons_codec_commons_codec_1_10.xml │ ├── Maven__javax_validation_validation_api_1_1_0_Final.xml │ ├── Maven__junit_junit_4_12.xml │ ├── Maven__mysql_mysql_connector_java_5_1_39.xml │ ├── Maven__net_minidev_accessors_smart_1_1.xml │ ├── Maven__net_minidev_json_smart_2_2_1.xml │ ├── Maven__org_apache_commons_commons_pool2_2_4_2.xml │ ├── Maven__org_apache_httpcomponents_httpclient_4_5_2.xml │ ├── Maven__org_apache_httpcomponents_httpcore_4_4_5.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_core_8_5_5.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_el_8_5_5.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_5_5.xml │ ├── Maven__org_apache_tomcat_tomcat_jdbc_8_5_5.xml │ ├── Maven__org_apache_tomcat_tomcat_juli_8_5_5.xml │ ├── Maven__org_assertj_assertj_core_2_5_0.xml │ ├── Maven__org_hamcrest_hamcrest_core_1_3.xml │ ├── Maven__org_hamcrest_hamcrest_library_1_3.xml │ ├── Maven__org_hibernate_hibernate_validator_5_2_4_Final.xml │ ├── Maven__org_jboss_logging_jboss_logging_3_3_0_Final.xml │ ├── Maven__org_json_json_20140107.xml │ ├── Maven__org_mockito_mockito_core_1_10_19.xml │ ├── Maven__org_mybatis_mybatis_3_4_0.xml │ ├── Maven__org_mybatis_mybatis_spring_1_3_0.xml │ ├── Maven__org_mybatis_spring_boot_mybatis_spring_boot_autoconfigure_1_1_1.xml │ ├── Maven__org_mybatis_spring_boot_mybatis_spring_boot_starter_1_1_1.xml │ ├── Maven__org_objenesis_objenesis_2_1.xml │ ├── Maven__org_ow2_asm_asm_5_0_3.xml │ ├── Maven__org_projectlombok_lombok_1_16_6.xml │ ├── Maven__org_skyscreamer_jsonassert_1_3_0.xml │ ├── Maven__org_slf4j_jcl_over_slf4j_1_7_21.xml │ ├── Maven__org_slf4j_jul_to_slf4j_1_7_21.xml │ ├── Maven__org_slf4j_log4j_over_slf4j_1_7_21.xml │ ├── Maven__org_slf4j_slf4j_api_1_7_21.xml │ ├── Maven__org_springframework_amqp_spring_amqp_1_6_2_RELEASE.xml │ ├── Maven__org_springframework_amqp_spring_rabbit_1_6_2_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_autoconfigure_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_amqp_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_jdbc_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_logging_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_redis_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_test_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_tomcat_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_web_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_test_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_test_autoconfigure_1_4_1_RELEASE.xml │ ├── Maven__org_springframework_data_spring_data_commons_1_12_3_RELEASE.xml │ ├── Maven__org_springframework_data_spring_data_keyvalue_1_1_3_RELEASE.xml │ ├── Maven__org_springframework_data_spring_data_redis_1_7_3_RELEASE.xml │ ├── Maven__org_springframework_retry_spring_retry_1_1_4_RELEASE.xml │ ├── Maven__org_springframework_spring_aop_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_beans_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_context_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_context_support_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_core_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_expression_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_jdbc_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_messaging_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_oxm_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_test_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_tx_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_web_4_3_3_RELEASE.xml │ ├── Maven__org_springframework_spring_webmvc_4_3_3_RELEASE.xml │ ├── Maven__org_yaml_snakeyaml_1_17.xml │ └── Maven__redis_clients_jedis_2_8_1.xml ├── misc.xml ├── modules.xml ├── smartfox_info.xml ├── uiDesigner.xml ├── vcs.xml └── workspace.xml ├── README.md ├── SecKillDesign.iml ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── scut │ │ └── seckill │ │ ├── SecKillApp.java │ │ ├── cache │ │ ├── RedisCacheHandle.java │ │ └── RedisLoaderListener.java │ │ ├── common │ │ ├── GlobalExceptionHandler.java │ │ ├── Head.java │ │ ├── Message.java │ │ └── SecKillEnum.java │ │ ├── concurrent │ │ └── AtomicStock.java │ │ ├── config │ │ ├── MyBatisConfig.java │ │ ├── RabbitmqCallBackConfig.java │ │ └── RedisCacheConfig.java │ │ ├── constant │ │ ├── RedisCacheConst.java │ │ └── SecKillStateConst.java │ │ ├── controller │ │ └── SecKillController.java │ │ ├── entity │ │ ├── Product.java │ │ ├── Record.java │ │ └── User.java │ │ ├── exception │ │ └── SecKillException.java │ │ ├── mapper │ │ └── SecKillMapper.java │ │ ├── mq │ │ ├── RabbitMQReceiver.java │ │ └── RabbitMQSender.java │ │ ├── service │ │ └── SecKillService.java │ │ ├── utils │ │ └── SecKillUtils.java │ │ └── web │ │ ├── req │ │ └── SecKillRequest.java │ │ └── vo │ │ └── SecKillResponse.java └── resources │ ├── application.properties │ ├── dao │ └── SecKillMapper.xml │ ├── jmeter │ ├── data-config.png │ ├── operation.txt │ ├── origin.png │ ├── param-repeat.txt │ ├── param.txt │ └── seckill.jmx │ ├── sql │ ├── insert.sql │ └── seckill.sql │ └── stress_test_result │ ├── atomicInteger │ ├── result_1.png │ ├── result_2.png │ └── result_3.png │ ├── pessLockInMySQL │ ├── result_1.png │ ├── result_2.png │ └── result_3.png │ ├── posiLockInMySQL │ ├── result_1.png │ ├── result_2.png │ └── result_3.png │ └── posiLockInRedis │ ├── result_1.png │ ├── result_2.png │ └── result_3.png └── test └── java └── JUnitTest.java /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 60 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__ch_qos_logback_logback_classic_1_1_7.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__ch_qos_logback_logback_core_1_1_7.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_alibaba_druid_1_0_18.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_alibaba_fastjson_1_2_31.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_classmate_1_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_8_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_8_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_8_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_rabbitmq_amqp_client_3_6_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_rabbitmq_http_client_1_0_0_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_codec_commons_codec_1_10.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_validation_validation_api_1_1_0_Final.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__junit_junit_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__mysql_mysql_connector_java_5_1_39.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_minidev_accessors_smart_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_minidev_json_smart_2_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_commons_commons_pool2_2_4_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_5_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_5_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_5_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_tomcat_jdbc_8_5_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_tomcat_juli_8_5_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_assertj_assertj_core_2_5_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_library_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hibernate_hibernate_validator_5_2_4_Final.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_3_0_Final.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_json_json_20140107.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mockito_mockito_core_1_10_19.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mybatis_mybatis_3_4_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mybatis_mybatis_spring_1_3_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mybatis_spring_boot_mybatis_spring_boot_autoconfigure_1_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mybatis_spring_boot_mybatis_spring_boot_starter_1_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_objenesis_objenesis_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_ow2_asm_asm_5_0_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_projectlombok_lombok_1_16_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_skyscreamer_jsonassert_1_3_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_jcl_over_slf4j_1_7_21.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_21.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_log4j_over_slf4j_1_7_21.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_21.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_amqp_spring_amqp_1_6_2_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_amqp_spring_rabbit_1_6_2_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_amqp_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_jdbc_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_redis_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_test_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_1_4_1_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_data_spring_data_commons_1_12_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_data_spring_data_keyvalue_1_1_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_data_spring_data_redis_1_7_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_retry_spring_retry_1_1_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_aop_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_beans_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_context_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_context_support_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_core_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_expression_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_jdbc_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_messaging_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_oxm_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_test_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_tx_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_web_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_webmvc_4_3_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_yaml_snakeyaml_1_17.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__redis_clients_jedis_2_8_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/smartfox_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Java秒杀与抢购模型的架构设计与实现 2 | ======================= 3 | 4 | 开发环境: 5 | ----------------------------------- 6 | IntelliJ IDEA + Maven + Workbench 7 | 8 | 压测工具: 9 | ----------------------------------- 10 | JMeter 11 | 12 | 使用框架: 13 | ----------------------------------- 14 | Spring Boot + Mybatis + Redis + RabbitMQ 15 | 16 | 具体内容: 17 | ----------------------------------- 18 | 对高并发高负载情形下的应用场景进行分析,以高效地处理资源竞争为目的,设计一个秒杀与抢购模型。 19 | 本项目提供了三种解决方案来比较系统的性能: 20 | 1.利用MySQL的update行锁实现悲观锁。 21 | 2.MySQL加字段version实现乐观锁。 22 | 3.基于AtomicInteger的CAS机制; 23 | 4.使用Redis作为原子计数器(watch事务+decr操作),RabbitMQ作为消息队列记录用户抢购行为,MySQL做异步存储。 24 | 上述四个解决方案均使用了JMeter进行压力与性能测试(实验设置的是10秒内产生3000个请求),分析其吞吐量、平均响应时间、错误率等参数,最后得出相应结论。 25 | 26 | 实验结果: 27 | ----------------------------------- 28 | 实验结果表明: 29 | 四种方案的响应错误率均为零,但是吞吐量不一样, 30 | 总体来说第一种和第四种方案的吞吐量相当,平均响应时间也较快; 31 | 第三种方案的吞吐量慢于上述两种,CAS机制效果不错。 32 | 第二种方案的响应时间最慢,原因是高并发情形下多个线程不断回滚,耗费了大量的CPU资源,导致性能低下。 33 | 34 | 35 | 备注: 36 | ----------------------------------- 37 | 1.此项目包含了sql文件,包括表单创建和添加数据。 38 | 2.包含了JMeter配置图片与实验结果图片 39 | 3.包含了测试数据集:param.txt。第一个参数代表用户ID,第二个参数代表产品ID。 40 | 41 | 核心代码: 42 | ----------------------------------- 43 | ### MySQL悲观锁 44 | @Transactional 45 | public SecKillEnum handleByPessLockInMySQL(Map paramMap) { 46 | Jedis jedis = redisCacheHandle.getJedis(); 47 | Record record = null; 48 | Integer userId = (Integer) paramMap.get("userId"); 49 | Integer productId = (Integer)paramMap.get("productId"); 50 | User user = new User(userId); 51 | Product product = secKillMapper.getProductById(productId); 52 | String hasBoughtSetKey = SecKillUtils.getRedisHasBoughtSetKey(product.getProductName()); 53 | 54 | //判断是否重复购买 55 | boolean isBuy = jedis.sismember(hasBoughtSetKey, user.getId().toString()); 56 | if (isBuy){ 57 | //重复秒杀 58 | throw new SecKillException(SecKillEnum.REPEAT); 59 | } 60 | boolean secKillSuccess = secKillMapper.updatePessLockInMySQL(product); 61 | if (!secKillSuccess){ 62 | //库存不足 63 | throw new SecKillException(SecKillEnum.LOW_STOCKS); 64 | } 65 | 66 | //秒杀成功 67 | record = new Record(null,user,product,SecKillEnum.SUCCESS.getCode(),SecKillEnum.SUCCESS.getMessage(),new Date()); 68 | log.info(record.toString()); 69 | boolean insertFlag = secKillMapper.insertRecord(record); 70 | //插入record成功 71 | if (insertFlag){ 72 | long addResult = jedis.sadd(hasBoughtSetKey,user.getId().toString()); 73 | if (addResult>0){ 74 | log.info("---------秒杀成功"); 75 | return SecKillEnum.SUCCESS; 76 | }else { 77 | throw new SecKillException(SecKillEnum.REPEAT); 78 | } 79 | }else { 80 | throw new SecKillException(SecKillEnum.SYSTEM_EXCEPTION); 81 | } 82 | } 83 | 84 | ### MySQL乐观锁 85 | @Transactional 86 | public SecKillEnum handleByPosiLockInMySQL(Map paramMap){ 87 | Jedis jedis = redisCacheHandle.getJedis(); 88 | Record record = null; 89 | Integer userId = (Integer) paramMap.get("userId"); 90 | Integer productId = (Integer)paramMap.get("productId"); 91 | User user = new User(userId); 92 | Product product = secKillMapper.getProductById(productId); 93 | String hasBoughtSetKey = SecKillUtils.getRedisHasBoughtSetKey(product.getProductName()); 94 | 95 | //判断是否重复购买 96 | boolean isBuy = jedis.sismember(hasBoughtSetKey, user.getId().toString()); 97 | if (isBuy){ 98 | //重复秒杀 99 | throw new SecKillException(SecKillEnum.REPEAT); 100 | } 101 | //库存减一 102 | int lastStock = product.getStock()-1; 103 | if (lastStock>=0){ 104 | product.setStock(lastStock); 105 | boolean secKillSuccess = secKillMapper.updatePosiLockInMySQL(product); 106 | if (!secKillSuccess){ 107 | //秒杀失败,version被修改 108 | throw new SecKillException(SecKillEnum.FAIL); 109 | } 110 | }else { 111 | //库存不足 112 | throw new SecKillException(SecKillEnum.LOW_STOCKS); 113 | } 114 | 115 | record = new Record(null,user,product,SecKillEnum.SUCCESS.getCode(),SecKillEnum.SUCCESS.getMessage(),new Date()); 116 | log.info(record.toString()); 117 | boolean insertFlag = secKillMapper.insertRecord(record); 118 | //插入record成功 119 | if (insertFlag){ 120 | long addResult = jedis.sadd(hasBoughtSetKey,user.getId().toString()); 121 | if (addResult>0){ 122 | //秒杀成功 123 | return SecKillEnum.SUCCESS; 124 | }else { 125 | //重复秒杀 126 | log.info("---------重复秒杀"); 127 | throw new SecKillException(SecKillEnum.REPEAT); 128 | } 129 | }else { 130 | //系统错误 131 | throw new SecKillException(SecKillEnum.SYSTEM_EXCEPTION); 132 | } 133 | } 134 | 135 | ### redis的watch监控 136 | public SecKillEnum handleByRedisWatch(Map paramMap) { 137 | Jedis jedis = redisCacheHandle.getJedis(); 138 | Record record = null; 139 | Integer userId = (Integer) paramMap.get("userId"); 140 | Integer productId = (Integer)paramMap.get("productId"); 141 | User user = new User(userId); 142 | String productName = jedis.get("product_"+productId); 143 | String productStockCacheKey = productName+"_stock"; 144 | String hasBoughtSetKey = SecKillUtils.getRedisHasBoughtSetKey(productName); 145 | 146 | //watch开启监控 147 | jedis.watch(productStockCacheKey); 148 | 149 | //判断是否重复购买,注意这里高并发情形下并不安全 150 | boolean isBuy = jedis.sismember(hasBoughtSetKey, user.getId().toString()); 151 | if (isBuy){ 152 | //重复秒杀 153 | throw new SecKillException(SecKillEnum.REPEAT); 154 | } 155 | 156 | String stock = jedis.get(productStockCacheKey); 157 | if (Integer.parseInt(stock)<=0) { 158 | //库存不足 159 | throw new SecKillException(SecKillEnum.LOW_STOCKS); 160 | } 161 | 162 | //开启Redis事务 163 | Transaction tx = jedis.multi(); 164 | //库存减一 165 | tx.decrBy(productStockCacheKey,1); 166 | //执行事务 167 | List resultList = tx.exec(); 168 | 169 | if (resultList == null || resultList.isEmpty()) { 170 | jedis.unwatch(); 171 | //watch监控被更改过----物品抢购失败; 172 | throw new SecKillException(SecKillEnum.FAIL); 173 | } 174 | 175 | //添加到已买队列 176 | long addResult = jedis.sadd(hasBoughtSetKey,user.getId().toString()); 177 | if (addResult>0){ 178 | Product product = new Product(productId); 179 | //秒杀成功 180 | record = new Record(null,user,product,SecKillEnum.SUCCESS.getCode(),SecKillEnum.SUCCESS.getMessage(),new Date()); 181 | //添加record到rabbitMQ消息队列 182 | rabbitMQSender.send(JSON.toJSONString(record)); 183 | //返回秒杀成功 184 | return SecKillEnum.SUCCESS; 185 | }else { 186 | //重复秒杀 187 | //这里抛出RuntimeException异常,redis的decr操作并不会回滚,所以需要手动incr回去 188 | jedis.incrBy(productStockCacheKey,1); 189 | throw new SecKillException(SecKillEnum.REPEAT); 190 | } 191 | } 192 | 193 | ### AtomicInteger的CAS机制 194 | @Transactional 195 | public SecKillEnum handleByAtomicInteger(Map paramMap) { 196 | Jedis jedis = redisCacheHandle.getJedis(); 197 | Record record; 198 | 199 | Integer userId = (Integer) paramMap.get("userId"); 200 | Integer productId = (Integer)paramMap.get("productId"); 201 | User user = secKillMapper.getUserById(userId); 202 | Product product = secKillMapper.getProductById(productId); 203 | 204 | String hasBoughtSetKey = SecKillUtils.getRedisHasBoughtSetKey(product.getProductName()); 205 | //判断是否重复购买 206 | boolean isBuy = jedis.sismember(hasBoughtSetKey, user.getId().toString()); 207 | if (isBuy){ 208 | log.error("用户:"+user.getUsername()+"重复购买商品"+product.getProductName()); 209 | throw new SecKillException(SecKillEnum.REPEAT); 210 | } 211 | 212 | AtomicInteger atomicInteger = atomicStock.getAtomicInteger(product.getProductName()); 213 | int stock = atomicInteger.decrementAndGet(); 214 | 215 | if (stock < 0) { 216 | log.error("商品:"+product.getProductName()+"库存不足, 抢购失败!"); 217 | throw new SecKillException(SecKillEnum.LOW_STOCKS); 218 | } 219 | 220 | 221 | long result = jedis.sadd(hasBoughtSetKey,user.getId().toString()); 222 | if (result > 0){ 223 | record = new Record(null,user,product,SecKillEnum.SUCCESS.getCode(),SecKillEnum.SUCCESS.getMessage(),new Date()); 224 | log.info(record.toString()); 225 | boolean insertFlag = secKillMapper.insertRecord(record); 226 | if (insertFlag) { 227 | //更改物品库存 228 | secKillMapper.updateByAsynPattern(record.getProduct()); 229 | log.info("用户:"+user.getUsername()+"秒杀商品"+product.getProductName()+"成功!"); 230 | return SecKillEnum.SUCCESS; 231 | } else { 232 | log.error("系统错误!"); 233 | throw new SecKillException(SecKillEnum.SYSTEM_EXCEPTION); 234 | } 235 | } else { 236 | log.error("用户:"+user.getUsername()+"重复秒杀商品"+product.getProductName()); 237 | atomicInteger.incrementAndGet(); 238 | throw new SecKillException(SecKillEnum.REPEAT); 239 | } 240 | } 241 | 242 | JMeter压测图片: 243 | ----------------------------------- 244 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/jmeter/origin.png "github") 245 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/jmeter/data-config.png "github") 246 | 247 | 实验结果图片: 248 | ----------------------------------- 249 | ### MySQL悲观锁 250 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/pessLockInMySQL/result_1.png "github") 251 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/pessLockInMySQL/result_2.png "github") 252 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/pessLockInMySQL/result_3.png "github") 253 | ##################################################################### 254 | 255 | ### MySQL乐观锁 256 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/posiLockInMySQL/result_1.png "github") 257 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/posiLockInMySQL/result_2.png "github") 258 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/posiLockInMySQL/result_3.png "github") 259 | ##################################################################### 260 | 261 | ### redis的watch监控 262 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/posiLockInRedis/result_1.png "github") 263 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/posiLockInRedis/result_2.png "github") 264 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/posiLockInRedis/result_3.png "github") 265 | ##################################################################### 266 | 267 | ### AtomicInteger的CAS机制 268 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/atomicInteger/result_1.png "github") 269 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/atomicInteger/result_2.png "github") 270 | ![github](https://github.com/SkyScraperTwc/SecKillDesign/blob/master/src/main/resources/stress_test_result/atomicInteger/result_3.png "github") -------------------------------------------------------------------------------- /SecKillDesign.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | groupId 8 | SecKillDesign 9 | 1.0-SNAPSHOT 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 1.4.1.RELEASE 15 | 16 | 17 | 18 | 19 | com.alibaba 20 | fastjson 21 | 1.2.31 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-redis 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-web 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-test 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-amqp 42 | 43 | 44 | 45 | junit 46 | junit 47 | 4.12 48 | 49 | 50 | 51 | org.projectlombok 52 | lombok 53 | 1.16.6 54 | 55 | 56 | 57 | org.slf4j 58 | slf4j-api 59 | 1.7.21 60 | 61 | 62 | 63 | com.alibaba 64 | druid 65 | 1.0.18 66 | 67 | 68 | 69 | mysql 70 | mysql-connector-java 71 | 5.1.39 72 | 73 | 74 | 75 | org.mybatis.spring.boot 76 | mybatis-spring-boot-starter 77 | 1.1.1 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | src/main/java 86 | 87 | **/*.properties 88 | **/*.xml 89 | 90 | false 91 | 92 | 93 | 94 | 95 | org.apache.maven.plugins 96 | maven-compiler-plugin 97 | 98 | 1.7 99 | 1.7 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/SecKillApp.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @MapperScan("com.scut.seckill.mapper") 9 | public class SecKillApp { 10 | public static void main(String[] args) { 11 | SpringApplication.run(SecKillApp.class,args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/cache/RedisCacheHandle.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.cache; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Component; 5 | import redis.clients.jedis.Jedis; 6 | import redis.clients.jedis.JedisPool; 7 | 8 | @Component 9 | public class RedisCacheHandle { 10 | 11 | @Autowired 12 | private JedisPool jedisPool; 13 | 14 | public Jedis getJedis(){ 15 | return jedisPool.getResource(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/cache/RedisLoaderListener.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.cache; 2 | 3 | import com.scut.seckill.entity.Product; 4 | import com.scut.seckill.mapper.SecKillMapper; 5 | import com.scut.seckill.concurrent.AtomicStock; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | import redis.clients.jedis.Jedis; 10 | 11 | import javax.annotation.PostConstruct; 12 | import java.util.List; 13 | 14 | @Slf4j 15 | @Component 16 | public class RedisLoaderListener { 17 | 18 | @Autowired 19 | private RedisCacheHandle redisCacheHandle; 20 | 21 | @Autowired 22 | private SecKillMapper secKillMapper; 23 | 24 | @Autowired 25 | private AtomicStock atomicStock; 26 | 27 | @PostConstruct 28 | public void initRedis(){ 29 | Jedis jedis = redisCacheHandle.getJedis(); 30 | //清空Redis缓存 31 | jedis.flushDB(); 32 | List productList = secKillMapper.getAllProduct(); 33 | for (Product product:productList) { 34 | jedis.set(product.getProductName()+"_stock", String.valueOf(product.getStock())); 35 | } 36 | log.info("Redis缓存数据初始化完毕!"); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/common/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.common; 2 | 3 | import com.scut.seckill.exception.SecKillException; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.web.bind.annotation.ControllerAdvice; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | @ControllerAdvice 10 | @Slf4j 11 | public class GlobalExceptionHandler { 12 | 13 | @ExceptionHandler(value = SecKillException.class) 14 | @ResponseBody 15 | public Message handleSecKillException(SecKillException secKillException){ 16 | log.info(secKillException.getSecKillEnum().getMessage()); 17 | return new Message(secKillException.getSecKillEnum()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/common/Head.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.common; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author twc 7 | */ 8 | @Data 9 | public class Head { 10 | 11 | /** 12 | * 状态码 13 | */ 14 | private String statusCode; 15 | 16 | /** 17 | * 状态信息 18 | */ 19 | private String statusMessage; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/common/Message.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.common; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class Message { 11 | 12 | private Head head; 13 | 14 | private T body; 15 | 16 | public Message(SecKillEnum resultEnum, T body){ 17 | this.head = new Head(); 18 | this.head.setStatusCode(resultEnum.getCode()); 19 | this.head.setStatusMessage(resultEnum.getMessage()); 20 | this.body = body; 21 | } 22 | 23 | public Message(SecKillEnum resultEnum){ 24 | this.head = new Head(); 25 | this.head.setStatusCode(resultEnum.getCode()); 26 | this.head.setStatusMessage(resultEnum.getMessage()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/common/SecKillEnum.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.common; 2 | 3 | 4 | import com.scut.seckill.constant.SecKillStateConst; 5 | 6 | /** 7 | * @author twc 8 | */ 9 | 10 | public enum SecKillEnum { 11 | /** 12 | * 服务级错误 13 | */ 14 | SUCCESS(SecKillStateConst.SUCCESS,"秒杀成功"), 15 | LOW_STOCKS(SecKillStateConst.FAIL, "库存不足"), 16 | FAIL(SecKillStateConst.FAIL, "秒杀失败"), 17 | REPEAT(SecKillStateConst.REPEAT, "重复秒杀"), 18 | SYSTEM_EXCEPTION(SecKillStateConst.SYSTEM_EXCEPTION, "系统错误"), 19 | ; 20 | 21 | private String code; 22 | 23 | private String message; 24 | 25 | SecKillEnum(String code, String message){ 26 | this.code = code; 27 | this.message = message; 28 | } 29 | 30 | public String getCode() { 31 | return code; 32 | } 33 | 34 | public String getMessage() { 35 | return message; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/concurrent/AtomicStock.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.concurrent; 2 | 3 | import com.scut.seckill.entity.Product; 4 | import com.scut.seckill.mapper.SecKillMapper; 5 | import lombok.Data; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.annotation.PostConstruct; 10 | import java.util.List; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | @Data 14 | @Component 15 | public class AtomicStock { 16 | 17 | private AtomicInteger samsungInteger = new AtomicInteger(); 18 | 19 | private AtomicInteger huaweiInteger = new AtomicInteger(); 20 | 21 | private AtomicInteger xiaomiInteger = new AtomicInteger(); 22 | 23 | private AtomicInteger iphoneInteger = new AtomicInteger(); 24 | 25 | @Autowired 26 | private SecKillMapper secKillMapper; 27 | 28 | @PostConstruct 29 | public void initAtomicInteger() { 30 | List productList = secKillMapper.getAllProduct(); 31 | for (Product product : productList) { 32 | getAtomicInteger(product.getProductName()).set(product.getStock()); 33 | 34 | } 35 | } 36 | 37 | public AtomicInteger getAtomicInteger(String productName) { 38 | AtomicInteger ai = null; 39 | if (productName != null && !productName.isEmpty()){ 40 | switch (productName){ 41 | case "iphone": 42 | ai = iphoneInteger; 43 | break; 44 | case "huawei": 45 | ai = huaweiInteger; 46 | break; 47 | case "samsung": 48 | ai = samsungInteger; 49 | break; 50 | case "xiaomi": 51 | ai = xiaomiInteger; 52 | break; 53 | } 54 | } 55 | return ai; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/config/MyBatisConfig.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.config; 2 | 3 | import com.alibaba.druid.pool.DruidDataSource; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.mybatis.spring.SqlSessionFactoryBean; 6 | import org.springframework.beans.factory.annotation.Qualifier; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 11 | import org.springframework.core.io.support.ResourcePatternResolver; 12 | 13 | import java.io.IOException; 14 | import java.sql.SQLException; 15 | 16 | @Configuration 17 | @Slf4j 18 | public class MyBatisConfig { 19 | 20 | @Value("${spring.datasource.url}") 21 | private String dbUrl; 22 | 23 | @Value("${spring.datasource.username}") 24 | private String username; 25 | 26 | @Value("${spring.datasource.password}") 27 | private String password; 28 | 29 | @Value("${spring.datasource.driver-class-name}") 30 | private String driverClassName; 31 | 32 | @Value("${spring.datasource.initialSize}") 33 | private int initialSize; 34 | 35 | @Value("${spring.datasource.minIdle}") 36 | private int minIdle; 37 | 38 | @Value("${spring.datasource.maxActive}") 39 | private int maxActive; 40 | 41 | @Value("${spring.datasource.maxWait}") 42 | private int maxWait; 43 | 44 | @Value("${spring.datasource.timeBetweenEvictionRunsMillis}") 45 | private int timeBetweenEvictionRunsMillis; 46 | 47 | @Value("${spring.datasource.minEvictableIdleTimeMillis}") 48 | private int minEvictableIdleTimeMillis; 49 | 50 | @Value("${spring.datasource.validationQuery}") 51 | private String validationQuery; 52 | 53 | @Value("${spring.datasource.testWhileIdle}") 54 | private boolean testWhileIdle; 55 | 56 | @Value("${spring.datasource.testOnBorrow}") 57 | private boolean testOnBorrow; 58 | 59 | @Value("${spring.datasource.testOnReturn}") 60 | private boolean testOnReturn; 61 | 62 | @Value("${spring.datasource.poolPreparedStatements}") 63 | private boolean poolPreparedStatements; 64 | 65 | @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}") 66 | private int maxPoolPreparedStatementPerConnectionSize; 67 | 68 | @Value("${spring.datasource.filters}") 69 | private String filters; 70 | 71 | @Value("${spring.datasource.connectionProperties}") 72 | private String connectionProperties; 73 | 74 | /** 75 | * mybatis 76 | */ 77 | @Value("${mybatis.type-aliases-package}") 78 | private String typeAliasesPackage; 79 | 80 | @Value("${mybatis.mapper-locations}") 81 | private String mapperLocations; 82 | 83 | @Bean(name = "druidDataSource") 84 | public DruidDataSource dataSource(){ 85 | DruidDataSource dataSource = new DruidDataSource(); 86 | 87 | dataSource.setUrl(dbUrl); 88 | dataSource.setUsername(username); 89 | dataSource.setPassword(password); 90 | dataSource.setDriverClassName(driverClassName); 91 | 92 | //configuration 93 | dataSource.setInitialSize(initialSize); 94 | dataSource.setMinIdle(minIdle); 95 | dataSource.setMaxActive(maxActive); 96 | dataSource.setMaxWait(maxWait); 97 | dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); 98 | dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); 99 | dataSource.setValidationQuery(validationQuery); 100 | dataSource.setTestWhileIdle(testWhileIdle); 101 | dataSource.setTestOnBorrow(testOnBorrow); 102 | dataSource.setTestOnReturn(testOnReturn); 103 | dataSource.setPoolPreparedStatements(poolPreparedStatements); 104 | dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); 105 | try { 106 | dataSource.setFilters(filters); 107 | } catch (SQLException e) { 108 | log.error("druid configuration initialization filter", e); 109 | } 110 | dataSource.setConnectionProperties(connectionProperties); 111 | 112 | return dataSource; 113 | } 114 | 115 | @Bean 116 | public SqlSessionFactoryBean initSqlSessionFactoryBean(@Qualifier("druidDataSource") DruidDataSource dataSource) throws IOException { 117 | SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); 118 | sessionFactoryBean.setDataSource(dataSource); 119 | sessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage); 120 | //添加XML目录 121 | ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 122 | sessionFactoryBean.setMapperLocations(resolver.getResources(mapperLocations)); 123 | return sessionFactoryBean; 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/config/RabbitmqCallBackConfig.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.config; 2 | 3 | import org.springframework.amqp.core.*; 4 | import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; 5 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 6 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 7 | import org.springframework.beans.factory.annotation.Qualifier; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.beans.factory.config.ConfigurableBeanFactory; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.context.annotation.Primary; 13 | import org.springframework.context.annotation.Scope; 14 | 15 | @Configuration 16 | public class RabbitmqCallBackConfig { 17 | 18 | @Value("${spring.rabbitmq.host}") 19 | private String address; 20 | 21 | @Value("${spring.rabbitmq.port}") 22 | private String port; 23 | 24 | @Value("${spring.rabbitmq.username}") 25 | private String username; 26 | 27 | @Value("${spring.rabbitmq.password}") 28 | private String password; 29 | 30 | @Value("${spring.rabbitmq.virtual-host}") 31 | private String virtualHost; 32 | 33 | @Value("${spring.rabbitmq.publisher-confirms}") 34 | private boolean publisherConfirms; 35 | 36 | @Value("${rabbitmq.config.exchangeName}") 37 | private String exchangeName; 38 | 39 | @Value("${rabbitmq.config.queueName}") 40 | private String queueName; 41 | 42 | @Value("${rabbitmq.config.routingKey}") 43 | private String routingKey; 44 | 45 | @Bean 46 | public ConnectionFactory initConnectionFactory(){ 47 | CachingConnectionFactory factory = new CachingConnectionFactory(); 48 | factory.setAddresses(address+":"+port); 49 | factory.setUsername(username); 50 | factory.setPassword(password); 51 | factory.setVirtualHost(virtualHost); 52 | factory.setPublisherConfirms(publisherConfirms); 53 | return factory; 54 | } 55 | 56 | //必须是prototype类型 57 | @Bean 58 | @Primary 59 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 60 | public RabbitTemplate initRabbitTemplate(@Qualifier("initConnectionFactory") ConnectionFactory connectionFactory){ 61 | return new RabbitTemplate(connectionFactory); 62 | } 63 | 64 | /** 65 | * 针对消费者配置 66 | * 1. 设置交换机类型 67 | * 2. 将队列绑定到交换机 68 | FanoutExchange: 将消息分发到所有的绑定队列,无routingkey的概念 69 | HeadersExchange :通过添加属性key-value匹配 70 | DirectExchange:按照routingkey分发到指定队列 71 | TopicExchange:多关键字匹配 72 | */ 73 | @Bean 74 | public DirectExchange defaultExchange() { 75 | return new DirectExchange(exchangeName); 76 | } 77 | @Bean 78 | public Queue queue() { 79 | return new Queue(queueName); 80 | } 81 | @Bean 82 | public Binding binding() { 83 | return BindingBuilder.bind(queue()).to(defaultExchange()).with(routingKey); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/config/RedisCacheConfig.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.config; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import redis.clients.jedis.JedisPool; 9 | import redis.clients.jedis.JedisPoolConfig; 10 | 11 | /** 12 | * @author twc 13 | */ 14 | @Configuration 15 | @Slf4j 16 | public class RedisCacheConfig { 17 | 18 | @Value("${spring.redis.host}") 19 | private String host; 20 | 21 | @Value("${spring.redis.port}") 22 | private int port; 23 | 24 | @Value("${spring.redis.pool.max-idle}") 25 | private int maxIdle; 26 | 27 | @Value("${spring.redis.pool.min-idle}") 28 | private int minIdle; 29 | 30 | @Value("${spring.redis.pool.max-wait}") 31 | private long maxWaitMillis; 32 | 33 | @Value("${spring.redis.pool.max-active}") 34 | private int maxActive; 35 | 36 | @Value("${spring.redis.timeout}") 37 | private int timeout; 38 | 39 | @Value("${spring.redis.database}") 40 | private int database; 41 | 42 | @Bean(name = "poolConfig") 43 | public JedisPoolConfig initJedisPoolConfig(){ 44 | log.info("JedisPoolConfig注入开始:"); 45 | JedisPoolConfig poolConfig = new JedisPoolConfig(); 46 | poolConfig.setMaxTotal(maxActive); 47 | poolConfig.setMaxIdle(maxIdle); 48 | poolConfig.setMaxWaitMillis(maxWaitMillis); 49 | poolConfig.setMinIdle(minIdle); 50 | poolConfig.setTestOnBorrow(true); 51 | poolConfig.setTestOnReturn(true); 52 | poolConfig.setBlockWhenExhausted(true); 53 | return poolConfig; 54 | } 55 | 56 | @Bean 57 | public JedisPool initJedisPool(@Qualifier("poolConfig") JedisPoolConfig poolConfig){ 58 | log.info("JedisPool注入开始:"); 59 | JedisPool jedisPool = new JedisPool(poolConfig,host,port,timeout); 60 | return jedisPool; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/constant/RedisCacheConst.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.constant; 2 | 3 | public final class RedisCacheConst { 4 | /** 5 | * 用户已买集合 6 | */ 7 | public final static String IPHONE_HAS_BOUGHT_SET = "iphone_has_bought_set"; 8 | 9 | public final static String HUAWEI_HAS_BOUGHT_SET = "huawei_has_bought_set"; 10 | 11 | public final static String SAMSUNG_HAS_BOUGHT_SET = "samsung_has_bought_set"; 12 | 13 | public final static String XIAOMI_HAS_BOUGHT_SET = "xiaomi_has_bought_set"; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/constant/SecKillStateConst.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.constant; 2 | 3 | public final class SecKillStateConst { 4 | /** 5 | * 秒杀成功 6 | */ 7 | public final static String SUCCESS = "1"; 8 | /** 9 | * 秒杀失败 10 | */ 11 | public final static String FAIL = "0"; 12 | /** 13 | * 重复秒杀 14 | */ 15 | public final static String REPEAT = "-1"; 16 | /** 17 | * 系统错误 18 | */ 19 | public final static String SYSTEM_EXCEPTION = "-2"; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/controller/SecKillController.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.controller; 2 | 3 | import com.scut.seckill.cache.RedisCacheHandle; 4 | import com.scut.seckill.common.Message; 5 | import com.scut.seckill.common.SecKillEnum; 6 | import com.scut.seckill.service.SecKillService; 7 | import com.scut.seckill.web.req.SecKillRequest; 8 | import com.scut.seckill.web.vo.SecKillResponse; 9 | import org.junit.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.web.bind.annotation.*; 12 | import redis.clients.jedis.Jedis; 13 | 14 | import java.util.HashMap; 15 | import java.util.HashSet; 16 | import java.util.Map; 17 | import java.util.Set; 18 | 19 | @RequestMapping("/seckill") 20 | @RestController 21 | public class SecKillController { 22 | 23 | @Autowired 24 | private SecKillService secKillService; 25 | 26 | /** 27 | * MySQL悲观锁 28 | * @param requestMessage 29 | * @return 30 | */ 31 | @RequestMapping(value = "/pessLockInMySQL",method = RequestMethod.POST) 32 | public Message pessLockInMySQL(@RequestBody Message requestMessage){ 33 | Map paramMap = new HashMap<>(); 34 | paramMap.put("userId",requestMessage.getBody().getUserId()); 35 | paramMap.put("productId",requestMessage.getBody().getProductId()); 36 | SecKillEnum secKillEnum = secKillService.handleByPessLockInMySQL(paramMap); 37 | Message responseMessage = new Message<>(secKillEnum,null); 38 | return responseMessage; 39 | } 40 | 41 | /** 42 | * MySQL乐观锁 43 | * @param requestMessage 44 | * @return 45 | */ 46 | @RequestMapping(value = "/posiLockInMySQL",method = RequestMethod.POST) 47 | public Message posiLockInMySQL(@RequestBody Message requestMessage){ 48 | Map paramMap = new HashMap<>(); 49 | paramMap.put("userId",requestMessage.getBody().getUserId()); 50 | paramMap.put("productId",requestMessage.getBody().getProductId()); 51 | SecKillEnum secKillEnum = secKillService.handleByPosiLockInMySQL(paramMap); 52 | Message responseMessage = new Message<>(secKillEnum,null); 53 | return responseMessage; 54 | } 55 | 56 | /** 57 | * 利用redis的watch监控的特性 58 | * @throws InterruptedException 59 | */ 60 | @RequestMapping(value = "/baseOnRedisWatch",method = RequestMethod.POST) 61 | public Message baseOnRedisWatch(@RequestBody Message requestMessage) throws InterruptedException { 62 | Map paramMap = new HashMap<>(); 63 | paramMap.put("userId",requestMessage.getBody().getUserId()); 64 | paramMap.put("productId",requestMessage.getBody().getProductId()); 65 | SecKillEnum secKillEnum = secKillService.handleByRedisWatch(paramMap); 66 | Message responseMessage = new Message<>(secKillEnum,null); 67 | return responseMessage; 68 | } 69 | 70 | /** 71 | * 利用AtomicInteger的CAS机制特性 72 | * @param requestMessage 73 | * @return 74 | */ 75 | @RequestMapping(value = "/baseOnAtomicInteger",method = RequestMethod.POST) 76 | public Message baseOnAtomicInteger(@RequestBody Message requestMessage){ 77 | Map paramMap = new HashMap<>(); 78 | paramMap.put("userId",requestMessage.getBody().getUserId()); 79 | paramMap.put("productId",requestMessage.getBody().getProductId()); 80 | SecKillEnum secKillEnum = secKillService.handleByAtomicInteger(paramMap); 81 | Message responseMessage = new Message<>(secKillEnum,null); 82 | return responseMessage; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/entity/Product.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.math.BigDecimal; 8 | import java.util.Date; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | public class Product { 14 | /** 15 | * id 16 | */ 17 | private Integer id; 18 | /** 19 | * 产品名称 20 | */ 21 | private String productName; 22 | /** 23 | * 价格 24 | */ 25 | private BigDecimal price; 26 | /** 27 | * 库存 28 | */ 29 | private int stock; 30 | /** 31 | * 版本号 32 | */ 33 | private int version; 34 | /** 35 | * 创建时间 36 | */ 37 | private Date createTime; 38 | 39 | public Product(Integer id){ 40 | this.id = id; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/entity/Record.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * 购买明细记录 11 | */ 12 | @Data 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class Record { 16 | /** 17 | * id 18 | */ 19 | private Integer id; 20 | /** 21 | * 用户 22 | */ 23 | private User user; 24 | /** 25 | * 产品 26 | */ 27 | private Product product; 28 | /** 29 | * 1秒杀成功,0秒杀失败,-1重复秒杀,-2系统异常 30 | */ 31 | private String state; 32 | /** 33 | * 状态的明文标识 34 | */ 35 | private String stateInfo; 36 | /** 37 | * 创建时间 38 | */ 39 | private Date createTime; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.math.BigDecimal; 8 | import java.util.Date; 9 | 10 | /** 11 | * @author twc 12 | */ 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class User { 17 | /** 18 | * 主键 19 | */ 20 | private Integer id; 21 | /** 22 | * 用户名 23 | */ 24 | private String username; 25 | /** 26 | * 手机号码 27 | */ 28 | private String phone; 29 | /** 30 | * 创建时间 31 | */ 32 | private Date createTime; 33 | 34 | public User(Integer id) { 35 | this.id = id; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/exception/SecKillException.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.exception; 2 | 3 | import com.scut.seckill.common.SecKillEnum; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class SecKillException extends RuntimeException { 8 | 9 | private SecKillEnum secKillEnum; 10 | 11 | public SecKillException(SecKillEnum secKillEnum){ 12 | this.secKillEnum = secKillEnum; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/mapper/SecKillMapper.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.mapper; 2 | 3 | import com.scut.seckill.entity.Product; 4 | import com.scut.seckill.entity.Record; 5 | import com.scut.seckill.entity.User; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | 10 | @Repository 11 | public interface SecKillMapper{ 12 | 13 | List getAllUser(); 14 | 15 | User getUserById(Integer id); 16 | 17 | List getAllProduct(); 18 | 19 | Product getProductById(Integer id); 20 | 21 | boolean updatePessLockInMySQL(Product product); 22 | 23 | boolean updatePosiLockInMySQL(Product product); 24 | 25 | boolean insertRecord(Record record); 26 | 27 | boolean updateByAsynPattern(Product product); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/mq/RabbitMQReceiver.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.mq; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.TypeReference; 5 | import com.scut.seckill.entity.Record; 6 | import com.scut.seckill.mapper.SecKillMapper; 7 | import org.springframework.amqp.rabbit.annotation.RabbitHandler; 8 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | @RabbitListener(queues = "seckillQueue") 14 | public class RabbitMQReceiver { 15 | 16 | @Autowired 17 | private SecKillMapper secKillMapper; 18 | 19 | @RabbitHandler 20 | public void process(String message) throws Exception { 21 | Record record = JSON.parseObject(message, new TypeReference(){}); 22 | //插入record 23 | secKillMapper.insertRecord(record); 24 | //更改物品库存 25 | secKillMapper.updateByAsynPattern(record.getProduct()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/mq/RabbitMQSender.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.mq; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 5 | import org.springframework.amqp.rabbit.support.CorrelationData; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.UUID; 10 | 11 | /** 12 | * 可靠确认模式 13 | */ 14 | @Slf4j 15 | @Component 16 | public class RabbitMQSender implements RabbitTemplate.ConfirmCallback{ 17 | 18 | @Autowired 19 | private RabbitTemplate rabbitTemplate; 20 | 21 | public void send(String message) { 22 | rabbitTemplate.setConfirmCallback(this); 23 | CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString()); 24 | rabbitTemplate.convertAndSend("seckillExchange", "seckillRoutingKey", message, correlationData); 25 | } 26 | 27 | @Override 28 | public void confirm(CorrelationData correlationData, boolean ack, String cause) { 29 | log.info("callbakck confirm: " + correlationData.getId()); 30 | if (ack){ 31 | log.info("插入record成功,更改库存成功"); 32 | }else{ 33 | log.info("cause:"+cause); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/service/SecKillService.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.service; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.scut.seckill.cache.RedisCacheHandle; 5 | import com.scut.seckill.common.SecKillEnum; 6 | import com.scut.seckill.concurrent.AtomicStock; 7 | import com.scut.seckill.entity.Product; 8 | import com.scut.seckill.entity.Record; 9 | import com.scut.seckill.entity.User; 10 | import com.scut.seckill.exception.SecKillException; 11 | import com.scut.seckill.mapper.SecKillMapper; 12 | import com.scut.seckill.mq.RabbitMQSender; 13 | import com.scut.seckill.utils.SecKillUtils; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.stereotype.Service; 17 | import org.springframework.transaction.annotation.Transactional; 18 | import redis.clients.jedis.Jedis; 19 | import redis.clients.jedis.Transaction; 20 | 21 | import java.util.Date; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.concurrent.atomic.AtomicInteger; 25 | 26 | @Slf4j 27 | @Service 28 | public class SecKillService { 29 | 30 | @Autowired 31 | private RedisCacheHandle redisCacheHandle; 32 | 33 | @Autowired 34 | private SecKillMapper secKillMapper; 35 | 36 | @Autowired 37 | private RabbitMQSender rabbitMQSender; 38 | 39 | @Autowired 40 | private AtomicStock atomicStock; 41 | 42 | /** 43 | * 利用MySQL的update行锁实现悲观锁 44 | * @param paramMap 45 | * @return 46 | */ 47 | @Transactional 48 | public SecKillEnum handleByPessLockInMySQL(Map paramMap) { 49 | Jedis jedis = redisCacheHandle.getJedis(); 50 | Record record; 51 | 52 | Integer userId = (Integer) paramMap.get("userId"); 53 | Integer productId = (Integer)paramMap.get("productId"); 54 | User user = secKillMapper.getUserById(userId); 55 | Product product = secKillMapper.getProductById(productId); 56 | 57 | String hasBoughtSetKey = SecKillUtils.getRedisHasBoughtSetKey(product.getProductName()); 58 | //判断是否重复购买 59 | boolean isBuy = jedis.sismember(hasBoughtSetKey, user.getId().toString()); 60 | if (isBuy){ 61 | log.error("用户:"+user.getUsername()+"重复购买商品"+product.getProductName()); 62 | throw new SecKillException(SecKillEnum.REPEAT); 63 | } 64 | boolean secKillSuccess = secKillMapper.updatePessLockInMySQL(product); 65 | if (!secKillSuccess){ 66 | log.error("商品:"+product.getProductName()+"库存不足!"); 67 | throw new SecKillException(SecKillEnum.LOW_STOCKS); 68 | } 69 | 70 | long result = jedis.sadd(hasBoughtSetKey,user.getId().toString()); 71 | if (result > 0){ 72 | record = new Record(null,user,product,SecKillEnum.SUCCESS.getCode(),SecKillEnum.SUCCESS.getMessage(),new Date()); 73 | log.info(record.toString()); 74 | boolean insertFlag = secKillMapper.insertRecord(record); 75 | if (insertFlag){ 76 | log.info("用户:"+user.getUsername()+"秒杀商品:"+product.getProductName()+"成功!"); 77 | return SecKillEnum.SUCCESS; 78 | }else { 79 | log.error("系统错误!"); 80 | throw new SecKillException(SecKillEnum.SYSTEM_EXCEPTION); 81 | } 82 | }else { 83 | log.error("用户:"+user.getUsername()+"重复秒杀商品"+product.getProductName()); 84 | throw new SecKillException(SecKillEnum.REPEAT); 85 | } 86 | } 87 | 88 | /** 89 | * MySQL加字段version实现乐观锁 90 | * @param paramMap 91 | * @return 92 | */ 93 | @Transactional 94 | public SecKillEnum handleByPosiLockInMySQL(Map paramMap){ 95 | Jedis jedis = redisCacheHandle.getJedis(); 96 | Record record = null; 97 | 98 | Integer userId = (Integer) paramMap.get("userId"); 99 | Integer productId = (Integer)paramMap.get("productId"); 100 | User user = secKillMapper.getUserById(userId); 101 | Product product = secKillMapper.getProductById(productId); 102 | 103 | String hasBoughtSetKey = SecKillUtils.getRedisHasBoughtSetKey(product.getProductName()); 104 | boolean isBuy = jedis.sismember(hasBoughtSetKey, user.getId().toString()); 105 | if (isBuy){ 106 | log.error("用户:"+user.getUsername()+"重复购买商品"+product.getProductName()); 107 | throw new SecKillException(SecKillEnum.REPEAT); 108 | } 109 | 110 | //库存手动减一 111 | int lastStock = product.getStock()-1; 112 | if (lastStock >= 0){ 113 | product.setStock(lastStock); 114 | boolean secKillSuccess = secKillMapper.updatePosiLockInMySQL(product); 115 | if (!secKillSuccess){ 116 | log.error("用户:"+user.getUsername()+"秒杀商品"+product.getProductName()+"失败!"); 117 | throw new SecKillException(SecKillEnum.FAIL); 118 | } 119 | } else { 120 | log.error("商品:"+product.getProductName()+"库存不足!"); 121 | throw new SecKillException(SecKillEnum.LOW_STOCKS); 122 | } 123 | 124 | long addResult = jedis.sadd(hasBoughtSetKey,user.getId().toString()); 125 | if (addResult > 0){ 126 | log.info(record.toString()); 127 | boolean insertFlag = secKillMapper.insertRecord(record); 128 | if (insertFlag){ 129 | log.info("用户:"+user.getUsername()+"秒杀商品"+product.getProductName()+"成功!"); 130 | return SecKillEnum.SUCCESS; 131 | } else { 132 | throw new SecKillException(SecKillEnum.SYSTEM_EXCEPTION); 133 | } 134 | } else { 135 | log.error("用户:"+user.getUsername()+"重复秒杀商品:"+product.getProductName()); 136 | throw new SecKillException(SecKillEnum.REPEAT); 137 | } 138 | 139 | 140 | } 141 | 142 | /** 143 | * redis的watch监控 144 | * @param paramMap 145 | * @return 146 | */ 147 | public SecKillEnum handleByRedisWatch(Map paramMap) { 148 | Jedis jedis = redisCacheHandle.getJedis(); 149 | Record record; 150 | 151 | Integer userId = (Integer) paramMap.get("userId"); 152 | Integer productId = (Integer)paramMap.get("productId"); 153 | User user = secKillMapper.getUserById(userId); 154 | Product product = secKillMapper.getProductById(productId); 155 | 156 | String productStockCacheKey = product.getProductName()+"_stock"; 157 | String hasBoughtSetKey = SecKillUtils.getRedisHasBoughtSetKey(product.getProductName()); 158 | 159 | //watch开启监控 160 | jedis.watch(productStockCacheKey); 161 | 162 | //判断是否重复购买,注意这里高并发情形下并不安全 163 | boolean isBuy = jedis.sismember(hasBoughtSetKey, user.getId().toString()); 164 | if (isBuy){ 165 | log.error("用户:"+user.getUsername()+"重复购买商品"+product.getProductName()); 166 | throw new SecKillException(SecKillEnum.REPEAT); 167 | } 168 | 169 | String stock = jedis.get(productStockCacheKey); 170 | if (Integer.parseInt(stock) <= 0) { 171 | log.error("商品:"+product.getProductName()+"库存不足!"); 172 | throw new SecKillException(SecKillEnum.LOW_STOCKS); 173 | } 174 | 175 | //开启Redis事务 176 | Transaction tx = jedis.multi(); 177 | //库存减一 178 | tx.decrBy(productStockCacheKey,1); 179 | //执行事务 180 | List resultList = tx.exec(); 181 | 182 | if (resultList == null || resultList.isEmpty()) { 183 | jedis.unwatch(); 184 | //watch监控被更改过----物品抢购失败; 185 | log.error("商品:"+product.getProductName()+",watch监控被更改,物品抢购失败"); 186 | throw new SecKillException(SecKillEnum.FAIL); 187 | } 188 | 189 | //添加到已买队列 190 | long addResult = jedis.sadd(hasBoughtSetKey,user.getId().toString()); 191 | if (addResult>0){ 192 | //秒杀成功 193 | record = new Record(null,user,product,SecKillEnum.SUCCESS.getCode(),SecKillEnum.SUCCESS.getMessage(),new Date()); 194 | //添加record到rabbitMQ消息队列 195 | rabbitMQSender.send(JSON.toJSONString(record)); 196 | //返回秒杀成功 197 | return SecKillEnum.SUCCESS; 198 | } else { 199 | //重复秒杀 200 | //这里抛出RuntimeException异常,redis的decr操作并不会回滚,所以需要手动incr回去 201 | jedis.incrBy(productStockCacheKey,1); 202 | throw new SecKillException(SecKillEnum.REPEAT); 203 | } 204 | } 205 | 206 | /** 207 | * AtomicInteger的CAS机制 208 | * @param paramMap 209 | * @return 210 | */ 211 | @Transactional 212 | public SecKillEnum handleByAtomicInteger(Map paramMap) { 213 | Jedis jedis = redisCacheHandle.getJedis(); 214 | Record record; 215 | 216 | Integer userId = (Integer) paramMap.get("userId"); 217 | Integer productId = (Integer)paramMap.get("productId"); 218 | User user = secKillMapper.getUserById(userId); 219 | Product product = secKillMapper.getProductById(productId); 220 | 221 | String hasBoughtSetKey = SecKillUtils.getRedisHasBoughtSetKey(product.getProductName()); 222 | //判断是否重复购买 223 | boolean isBuy = jedis.sismember(hasBoughtSetKey, user.getId().toString()); 224 | if (isBuy){ 225 | log.error("用户:"+user.getUsername()+"重复购买商品"+product.getProductName()); 226 | throw new SecKillException(SecKillEnum.REPEAT); 227 | } 228 | 229 | AtomicInteger atomicInteger = atomicStock.getAtomicInteger(product.getProductName()); 230 | int stock = atomicInteger.decrementAndGet(); 231 | 232 | if (stock < 0) { 233 | log.error("商品:"+product.getProductName()+"库存不足, 抢购失败!"); 234 | throw new SecKillException(SecKillEnum.LOW_STOCKS); 235 | } 236 | 237 | 238 | long result = jedis.sadd(hasBoughtSetKey,user.getId().toString()); 239 | if (result > 0){ 240 | record = new Record(null,user,product,SecKillEnum.SUCCESS.getCode(),SecKillEnum.SUCCESS.getMessage(),new Date()); 241 | log.info(record.toString()); 242 | boolean insertFlag = secKillMapper.insertRecord(record); 243 | if (insertFlag) { 244 | //更改物品库存 245 | secKillMapper.updateByAsynPattern(record.getProduct()); 246 | log.info("用户:"+user.getUsername()+"秒杀商品"+product.getProductName()+"成功!"); 247 | return SecKillEnum.SUCCESS; 248 | } else { 249 | log.error("系统错误!"); 250 | throw new SecKillException(SecKillEnum.SYSTEM_EXCEPTION); 251 | } 252 | } else { 253 | log.error("用户:"+user.getUsername()+"重复秒杀商品"+product.getProductName()); 254 | atomicInteger.incrementAndGet(); 255 | throw new SecKillException(SecKillEnum.REPEAT); 256 | } 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/utils/SecKillUtils.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.utils; 2 | 3 | import com.scut.seckill.constant.RedisCacheConst; 4 | 5 | public class SecKillUtils { 6 | 7 | /** 8 | * 获取用户已买队列key 9 | * @param productName 10 | * @return 11 | */ 12 | public static String getRedisHasBoughtSetKey(String productName){ 13 | String hasBySet = ""; 14 | if (productName!=null && !productName.isEmpty()){ 15 | switch (productName){ 16 | case "iphone": 17 | hasBySet = RedisCacheConst.IPHONE_HAS_BOUGHT_SET; 18 | break; 19 | case "huawei": 20 | hasBySet = RedisCacheConst.HUAWEI_HAS_BOUGHT_SET; 21 | break; 22 | case "samsung": 23 | hasBySet = RedisCacheConst.SAMSUNG_HAS_BOUGHT_SET; 24 | break; 25 | case "xiaomi": 26 | hasBySet = RedisCacheConst.XIAOMI_HAS_BOUGHT_SET; 27 | break; 28 | } 29 | } 30 | return hasBySet; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/web/req/SecKillRequest.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.web.req; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class SecKillRequest { 11 | 12 | private Integer userId; 13 | 14 | private Integer productId; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/scut/seckill/web/vo/SecKillResponse.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill.web.vo; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class SecKillResponse { 7 | //todo 这里可以添加想要返回的字段,这里返回一个 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #上下文配置 2 | server.port=8080 3 | server.context-path=/SecKillDesign 4 | 5 | # 数据库访问配置 6 | # 主数据源,默认的 7 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 8 | spring.datasource.url=jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf8&useSSL=false 9 | spring.datasource.username=root 10 | spring.datasource.password=123456 11 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 12 | 13 | # 下面为连接池的补充设置,应用到上面所有数据源中 14 | # 初始化大小,最小,最大 15 | spring.datasource.initialSize=5 16 | #最小空闲数 17 | spring.datasource.minIdle=5 18 | #最大连接数 19 | spring.datasource.maxActive=40000 20 | # 配置获取连接等待超时的时间 21 | spring.datasource.maxWait=60000 22 | # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 23 | spring.datasource.timeBetweenEvictionRunsMillis=2000 24 | # 配置一个连接在池中最小生存的时间,单位是毫秒 25 | spring.datasource.minEvictableIdleTimeMillis=300000 26 | spring.datasource.validationQuery=SELECT 1 FROM DUAL 27 | spring.datasource.testWhileIdle=true 28 | spring.datasource.testOnBorrow=true 29 | spring.datasource.testOnReturn=true 30 | # 打开PSCache,并且指定每个连接上PSCache的大小 31 | spring.datasource.poolPreparedStatements=true 32 | spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 33 | # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 34 | spring.datasource.filters=stat,wall,log4j 35 | # 通过connectProperties属性来打开mergeSql功能;慢SQL记录 36 | spring.datasource.connectionProperties=druid.stat.mergeSql=true; 37 | # 合并多个DruidDataSource的监控数据 38 | #spring.datasource.useGlobalDataSourceStat=true 39 | 40 | # REDIS (RedisProperties) 41 | # Redis数据库索引(默认为0) 42 | spring.redis.database=0 43 | # Redis服务器地址 44 | spring.redis.host=127.0.0.1 45 | # Redis服务器连接端口 46 | spring.redis.port=6379 47 | # Redis服务器连接密码(默认为空) 48 | #spring.redis.password=redis 49 | # 连接池最大连接数(使用负值表示没有限制) 50 | spring.redis.pool.max-active=3000 51 | # 连接池最大阻塞等待时间(使用负值表示没有限制) 52 | spring.redis.pool.max-wait=-1 53 | # 连接池中的最大空闲连接 54 | spring.redis.pool.max-idle=8 55 | # 连接池中的最小空闲连接 56 | spring.redis.pool.min-idle=0 57 | # 连接超时时间(毫秒) 58 | spring.redis.timeout=0 59 | 60 | #rabbitmq上下文配置 61 | spring.rabbitmq.host=127.0.0.1 62 | spring.rabbitmq.port=5672 63 | spring.rabbitmq.username=guest 64 | spring.rabbitmq.password=guest 65 | spring.rabbitmq.publisher-confirms=true 66 | spring.rabbitmq.virtual-host=/ 67 | 68 | rabbitmq.config.exchangeName=seckillExchange 69 | rabbitmq.config.queueName=seckillQueue 70 | rabbitmq.config.routingKey=seckillRoutingKey 71 | 72 | #为entity包下的类起别名 73 | mybatis.type-aliases-package=com.scut.seckill.entity 74 | #mapper扫描位置 75 | mybatis.mapper-locations = classpath:dao/*.xml 76 | -------------------------------------------------------------------------------- /src/main/resources/dao/SecKillMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | update product set stock=stock-1 10 | where id=#{id} and stock>0 11 | 12 | 13 | 14 | update product set stock=#{stock},version=version+1 15 | where id=#{id} AND version=#{version} 16 | 17 | 18 | 19 | update product set stock=stock-1 where id=#{id} 20 | 21 | 22 | 25 | 26 | 29 | 30 | 33 | 34 | 37 | 38 | 39 | insert into record(userId, productId, state, stateInfo, createTime) 40 | values(#{user.id}, #{product.id}, #{state}, #{stateInfo}, #{createTime}) 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/jmeter/data-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/jmeter/data-config.png -------------------------------------------------------------------------------- /src/main/resources/jmeter/operation.txt: -------------------------------------------------------------------------------- 1 | { 2 | "head":{}, 3 | "body":{ 4 | "userId":${userId}, 5 | "productId":${productId} 6 | } 7 | } 8 | 9 | 这是本人此项目的github地址:https://github.com/SkyScraperTwc/SecKillDesign,希望各位能点Star,也欢迎Pull Request! 10 | 项目提供了SQL文件和JMeter压测参数等文件,代码也都有详细的注释! 11 | 我的项目提供了三种解决方案来实现秒杀系统: 12 | 1.利用MySQL实现悲观锁。 13 | 2.利用MySQL实现乐观锁。 14 | 3.基于AtomicInteger的CAS机制。 15 | 4.使用Redis作为原子计数器(watch事务+decr操作),RabbitMQ作为消息队列记录用户抢购行为,MySQL做异步存储。 16 | 最后使用JMeter进行性能测试,分析其吞吐量、平均响应时间、错误率等参数,得出相应结论。 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/resources/jmeter/origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/jmeter/origin.png -------------------------------------------------------------------------------- /src/main/resources/jmeter/param-repeat.txt: -------------------------------------------------------------------------------- 1 | 1,1 2 | 1,1 3 | 1,1 4 | 1,1 5 | 1,1 6 | 1,1 7 | 1,1 8 | 1,1 9 | 1,1 10 | 1,1 11 | 1,1 12 | 1,1 13 | 1,1 14 | 1,1 15 | 1,1 16 | 1,1 17 | 1,1 18 | 1,1 19 | 1,1 20 | 1,1 21 | 1,1 22 | 1,1 23 | 1,1 24 | 1,1 25 | 1,1 26 | 1,1 27 | 1,1 28 | 1,1 29 | 1,1 30 | 1,1 31 | 1,1 32 | 1,1 33 | 1,1 34 | 1,1 35 | 1,1 36 | 1,1 37 | 1,1 38 | 1,1 39 | 1,1 40 | 1,1 41 | 1,1 42 | 1,1 43 | 1,1 44 | 1,1 45 | 1,1 46 | 1,1 47 | 1,1 48 | 1,1 49 | 1,1 50 | 1,1 51 | 1,1 52 | 1,1 53 | 1,1 54 | 1,1 55 | 1,1 56 | 1,1 57 | 1,1 58 | 1,1 59 | 1,1 60 | 1,1 61 | 1,1 62 | 1,1 63 | 1,1 64 | 1,1 65 | 1,1 66 | 1,1 67 | 1,1 68 | 1,1 69 | 1,1 70 | 1,1 71 | 1,1 72 | 1,1 73 | 1,1 74 | 1,1 75 | 1,1 76 | 1,1 77 | 1,1 78 | 1,1 79 | 1,1 80 | 1,1 81 | 1,1 82 | 1,1 83 | 1,1 84 | 1,1 85 | 1,1 86 | 1,1 87 | 1,1 88 | 1,1 89 | 1,1 90 | 1,1 91 | 1,1 92 | 1,1 93 | 1,1 94 | 1,1 95 | 1,1 96 | 1,1 97 | 1,1 98 | 1,1 99 | 1,1 100 | 1,1 101 | 1,1 102 | 1,1 103 | 1,1 104 | 1,1 105 | 1,1 106 | 1,1 107 | 1,1 108 | 1,1 109 | 1,1 110 | 1,1 111 | 1,1 112 | 1,1 113 | 1,1 114 | 1,1 115 | 1,1 116 | 1,1 117 | 1,1 118 | 1,1 119 | 1,1 120 | 1,1 121 | 1,1 122 | 1,1 123 | 1,1 124 | 1,1 125 | 1,1 126 | 1,1 127 | 1,1 128 | 1,1 129 | 1,1 130 | 1,1 131 | 1,1 132 | 1,1 133 | 1,1 134 | 1,1 135 | 1,1 136 | 1,1 137 | 1,1 138 | 1,1 139 | 1,1 140 | 1,1 141 | 1,1 142 | 1,1 143 | 1,1 144 | 1,1 145 | 1,1 146 | 1,1 147 | 1,1 148 | 1,1 149 | 1,1 150 | 1,1 151 | 1,1 152 | 1,1 153 | 1,1 154 | 1,1 155 | 1,1 156 | 1,1 157 | 1,1 158 | 1,1 159 | 1,1 160 | 1,1 161 | 1,1 162 | 1,1 163 | 1,1 164 | 1,1 165 | 1,1 166 | 1,1 167 | 1,1 168 | 1,1 169 | 1,1 170 | 1,1 171 | 1,1 172 | 1,1 173 | 1,1 174 | 1,1 175 | 1,1 176 | 1,1 177 | 1,1 178 | 1,1 179 | 1,1 180 | 1,1 181 | 1,1 182 | 1,1 183 | 1,1 184 | 1,1 185 | 1,1 186 | 1,1 187 | 1,1 188 | 1,1 189 | 1,1 190 | 1,1 191 | 1,1 192 | 1,1 193 | 1,1 194 | 1,1 195 | 1,1 196 | 1,1 197 | 1,1 198 | 1,1 199 | 1,1 200 | 1,1 -------------------------------------------------------------------------------- /src/main/resources/jmeter/param.txt: -------------------------------------------------------------------------------- 1 | 1,2 2 | 2,1 3 | 3,2 4 | 4,1 5 | 5,2 6 | 6,2 7 | 7,1 8 | 8,2 9 | 9,4 10 | 10,3 11 | 11,2 12 | 12,3 13 | 13,3 14 | 14,4 15 | 15,1 16 | 16,4 17 | 17,3 18 | 18,4 19 | 19,3 20 | 20,4 21 | 21,1 22 | 22,4 23 | 23,3 24 | 24,4 25 | 25,3 26 | 26,3 27 | 27,4 28 | 28,3 29 | 29,3 30 | 30,2 31 | 31,2 32 | 32,2 33 | 33,2 34 | 34,1 35 | 35,3 36 | 36,3 37 | 37,1 38 | 38,4 39 | 39,2 40 | 40,3 41 | 41,4 42 | 42,4 43 | 43,2 44 | 44,4 45 | 45,2 46 | 46,3 47 | 47,2 48 | 48,2 49 | 49,4 50 | 50,2 51 | 51,3 52 | 52,3 53 | 53,3 54 | 54,2 55 | 55,3 56 | 56,1 57 | 57,4 58 | 58,1 59 | 59,3 60 | 60,1 61 | 61,1 62 | 62,2 63 | 63,1 64 | 64,2 65 | 65,2 66 | 66,2 67 | 67,1 68 | 68,1 69 | 69,1 70 | 70,1 71 | 71,2 72 | 72,3 73 | 73,3 74 | 74,4 75 | 75,1 76 | 76,3 77 | 77,3 78 | 78,1 79 | 79,2 80 | 80,1 81 | 81,3 82 | 82,4 83 | 83,2 84 | 84,2 85 | 85,2 86 | 86,2 87 | 87,1 88 | 88,4 89 | 89,1 90 | 90,2 91 | 91,4 92 | 92,4 93 | 93,1 94 | 94,3 95 | 95,4 96 | 96,1 97 | 97,1 98 | 98,3 99 | 99,2 100 | 100,3 101 | 101,4 102 | 102,2 103 | 103,2 104 | 104,2 105 | 105,2 106 | 106,2 107 | 107,2 108 | 108,2 109 | 109,3 110 | 110,3 111 | 111,3 112 | 112,3 113 | 113,4 114 | 114,3 115 | 115,4 116 | 116,4 117 | 117,4 118 | 118,1 119 | 119,4 120 | 120,1 121 | 121,2 122 | 122,4 123 | 123,4 124 | 124,4 125 | 125,4 126 | 126,4 127 | 127,1 128 | 128,2 129 | 129,3 130 | 130,1 131 | 131,4 132 | 132,2 133 | 133,3 134 | 134,3 135 | 135,4 136 | 136,3 137 | 137,3 138 | 138,1 139 | 139,3 140 | 140,3 141 | 141,4 142 | 142,2 143 | 143,2 144 | 144,1 145 | 145,3 146 | 146,4 147 | 147,2 148 | 148,4 149 | 149,2 150 | 150,3 151 | 151,3 152 | 152,1 153 | 153,2 154 | 154,2 155 | 155,1 156 | 156,4 157 | 157,4 158 | 158,2 159 | 159,4 160 | 160,3 161 | 161,4 162 | 162,3 163 | 163,4 164 | 164,3 165 | 165,3 166 | 166,2 167 | 167,4 168 | 168,1 169 | 169,2 170 | 170,1 171 | 171,4 172 | 172,4 173 | 173,1 174 | 174,3 175 | 175,3 176 | 176,2 177 | 177,2 178 | 178,1 179 | 179,4 180 | 180,3 181 | 181,2 182 | 182,4 183 | 183,1 184 | 184,1 185 | 185,3 186 | 186,2 187 | 187,4 188 | 188,2 189 | 189,4 190 | 190,1 191 | 191,1 192 | 192,4 193 | 193,1 194 | 194,3 195 | 195,3 196 | 196,1 197 | 197,4 198 | 198,1 199 | 199,3 200 | 200,4 201 | 201,3 202 | 202,1 203 | 203,4 204 | 204,3 205 | 205,1 206 | 206,1 207 | 207,1 208 | 208,3 209 | 209,3 210 | 210,1 211 | 211,2 212 | 212,4 213 | 213,2 214 | 214,3 215 | 215,2 216 | 216,2 217 | 217,4 218 | 218,1 219 | 219,4 220 | 220,2 221 | 221,4 222 | 222,4 223 | 223,3 224 | 224,1 225 | 225,4 226 | 226,4 227 | 227,3 228 | 228,2 229 | 229,4 230 | 230,2 231 | 231,4 232 | 232,1 233 | 233,2 234 | 234,3 235 | 235,4 236 | 236,4 237 | 237,2 238 | 238,2 239 | 239,4 240 | 240,4 241 | 241,3 242 | 242,2 243 | 243,3 244 | 244,3 245 | 245,4 246 | 246,2 247 | 247,3 248 | 248,2 249 | 249,3 250 | 250,3 251 | 251,3 252 | 252,1 253 | 253,1 254 | 254,3 255 | 255,3 256 | 256,1 257 | 257,3 258 | 258,2 259 | 259,4 260 | 260,2 261 | 261,3 262 | 262,2 263 | 263,4 264 | 264,2 265 | 265,1 266 | 266,1 267 | 267,3 268 | 268,4 269 | 269,4 270 | 270,3 271 | 271,3 272 | 272,1 273 | 273,1 274 | 274,2 275 | 275,1 276 | 276,4 277 | 277,1 278 | 278,2 279 | 279,3 280 | 280,1 281 | 281,1 282 | 282,2 283 | 283,4 284 | 284,2 285 | 285,2 286 | 286,2 287 | 287,3 288 | 288,3 289 | 289,4 290 | 290,3 291 | 291,4 292 | 292,3 293 | 293,1 294 | 294,4 295 | 295,4 296 | 296,4 297 | 297,4 298 | 298,3 299 | 299,3 300 | 300,1 301 | 301,4 302 | 302,2 303 | 303,3 304 | 304,4 305 | 305,2 306 | 306,3 307 | 307,4 308 | 308,4 309 | 309,2 310 | 310,2 311 | 311,2 312 | 312,3 313 | 313,3 314 | 314,3 315 | 315,3 316 | 316,1 317 | 317,4 318 | 318,3 319 | 319,3 320 | 320,1 321 | 321,1 322 | 322,2 323 | 323,3 324 | 324,3 325 | 325,3 326 | 326,3 327 | 327,4 328 | 328,3 329 | 329,2 330 | 330,1 331 | 331,3 332 | 332,3 333 | 333,2 334 | 334,3 335 | 335,2 336 | 336,3 337 | 337,4 338 | 338,1 339 | 339,4 340 | 340,2 341 | 341,2 342 | 342,1 343 | 343,1 344 | 344,2 345 | 345,1 346 | 346,1 347 | 347,1 348 | 348,3 349 | 349,2 350 | 350,2 351 | 351,2 352 | 352,3 353 | 353,2 354 | 354,1 355 | 355,3 356 | 356,4 357 | 357,3 358 | 358,2 359 | 359,2 360 | 360,2 361 | 361,1 362 | 362,1 363 | 363,1 364 | 364,2 365 | 365,3 366 | 366,3 367 | 367,4 368 | 368,1 369 | 369,1 370 | 370,2 371 | 371,1 372 | 372,2 373 | 373,2 374 | 374,4 375 | 375,1 376 | 376,4 377 | 377,1 378 | 378,2 379 | 379,4 380 | 380,3 381 | 381,4 382 | 382,4 383 | 383,2 384 | 384,1 385 | 385,4 386 | 386,1 387 | 387,1 388 | 388,4 389 | 389,1 390 | 390,1 391 | 391,4 392 | 392,3 393 | 393,2 394 | 394,3 395 | 395,1 396 | 396,4 397 | 397,4 398 | 398,1 399 | 399,1 400 | 400,2 401 | 401,2 402 | 402,2 403 | 403,1 404 | 404,3 405 | 405,4 406 | 406,2 407 | 407,1 408 | 408,2 409 | 409,2 410 | 410,2 411 | 411,3 412 | 412,4 413 | 413,1 414 | 414,3 415 | 415,1 416 | 416,1 417 | 417,1 418 | 418,3 419 | 419,4 420 | 420,4 421 | 421,1 422 | 422,1 423 | 423,2 424 | 424,2 425 | 425,3 426 | 426,2 427 | 427,1 428 | 428,1 429 | 429,3 430 | 430,4 431 | 431,3 432 | 432,4 433 | 433,3 434 | 434,3 435 | 435,4 436 | 436,1 437 | 437,3 438 | 438,4 439 | 439,1 440 | 440,1 441 | 441,4 442 | 442,4 443 | 443,1 444 | 444,3 445 | 445,3 446 | 446,2 447 | 447,4 448 | 448,3 449 | 449,4 450 | 450,1 451 | 451,3 452 | 452,4 453 | 453,1 454 | 454,1 455 | 455,1 456 | 456,1 457 | 457,2 458 | 458,3 459 | 459,2 460 | 460,1 461 | 461,3 462 | 462,1 463 | 463,1 464 | 464,1 465 | 465,4 466 | 466,2 467 | 467,2 468 | 468,3 469 | 469,3 470 | 470,2 471 | 471,3 472 | 472,1 473 | 473,4 474 | 474,1 475 | 475,3 476 | 476,2 477 | 477,1 478 | 478,2 479 | 479,4 480 | 480,4 481 | 481,2 482 | 482,4 483 | 483,3 484 | 484,2 485 | 485,4 486 | 486,3 487 | 487,2 488 | 488,3 489 | 489,4 490 | 490,2 491 | 491,4 492 | 492,3 493 | 493,2 494 | 494,2 495 | 495,4 496 | 496,1 497 | 497,3 498 | 498,4 499 | 499,4 500 | 500,3 501 | 501,3 502 | 502,4 503 | 503,2 504 | 504,2 505 | 505,3 506 | 506,3 507 | 507,4 508 | 508,4 509 | 509,1 510 | 510,3 511 | 511,3 512 | 512,1 513 | 513,3 514 | 514,1 515 | 515,4 516 | 516,4 517 | 517,4 518 | 518,1 519 | 519,4 520 | 520,3 521 | 521,1 522 | 522,4 523 | 523,1 524 | 524,4 525 | 525,1 526 | 526,4 527 | 527,3 528 | 528,4 529 | 529,2 530 | 530,3 531 | 531,3 532 | 532,4 533 | 533,1 534 | 534,2 535 | 535,2 536 | 536,1 537 | 537,2 538 | 538,1 539 | 539,3 540 | 540,3 541 | 541,1 542 | 542,1 543 | 543,4 544 | 544,2 545 | 545,4 546 | 546,3 547 | 547,4 548 | 548,4 549 | 549,1 550 | 550,2 551 | 551,1 552 | 552,1 553 | 553,1 554 | 554,1 555 | 555,3 556 | 556,3 557 | 557,1 558 | 558,4 559 | 559,2 560 | 560,3 561 | 561,2 562 | 562,1 563 | 563,4 564 | 564,2 565 | 565,1 566 | 566,3 567 | 567,3 568 | 568,2 569 | 569,4 570 | 570,2 571 | 571,2 572 | 572,4 573 | 573,1 574 | 574,1 575 | 575,2 576 | 576,3 577 | 577,2 578 | 578,2 579 | 579,3 580 | 580,1 581 | 581,1 582 | 582,1 583 | 583,3 584 | 584,2 585 | 585,2 586 | 586,1 587 | 587,4 588 | 588,1 589 | 589,4 590 | 590,1 591 | 591,4 592 | 592,1 593 | 593,4 594 | 594,3 595 | 595,4 596 | 596,2 597 | 597,2 598 | 598,1 599 | 599,2 600 | 600,4 601 | 601,2 602 | 602,1 603 | 603,1 604 | 604,3 605 | 605,1 606 | 606,1 607 | 607,4 608 | 608,1 609 | 609,4 610 | 610,2 611 | 611,1 612 | 612,4 613 | 613,4 614 | 614,4 615 | 615,4 616 | 616,4 617 | 617,2 618 | 618,3 619 | 619,2 620 | 620,2 621 | 621,4 622 | 622,1 623 | 623,1 624 | 624,4 625 | 625,2 626 | 626,3 627 | 627,1 628 | 628,1 629 | 629,1 630 | 630,4 631 | 631,1 632 | 632,4 633 | 633,3 634 | 634,2 635 | 635,1 636 | 636,4 637 | 637,3 638 | 638,1 639 | 639,3 640 | 640,3 641 | 641,3 642 | 642,2 643 | 643,2 644 | 644,3 645 | 645,2 646 | 646,2 647 | 647,1 648 | 648,1 649 | 649,2 650 | 650,4 651 | 651,2 652 | 652,3 653 | 653,4 654 | 654,2 655 | 655,2 656 | 656,2 657 | 657,3 658 | 658,1 659 | 659,1 660 | 660,3 661 | 661,3 662 | 662,4 663 | 663,1 664 | 664,4 665 | 665,1 666 | 666,2 667 | 667,2 668 | 668,3 669 | 669,4 670 | 670,4 671 | 671,3 672 | 672,2 673 | 673,1 674 | 674,3 675 | 675,1 676 | 676,4 677 | 677,2 678 | 678,1 679 | 679,1 680 | 680,4 681 | 681,3 682 | 682,3 683 | 683,1 684 | 684,2 685 | 685,4 686 | 686,1 687 | 687,2 688 | 688,4 689 | 689,1 690 | 690,3 691 | 691,4 692 | 692,3 693 | 693,1 694 | 694,3 695 | 695,4 696 | 696,4 697 | 697,4 698 | 698,1 699 | 699,4 700 | 700,2 701 | 701,1 702 | 702,1 703 | 703,1 704 | 704,3 705 | 705,2 706 | 706,4 707 | 707,2 708 | 708,4 709 | 709,1 710 | 710,3 711 | 711,4 712 | 712,1 713 | 713,1 714 | 714,4 715 | 715,3 716 | 716,2 717 | 717,2 718 | 718,3 719 | 719,4 720 | 720,1 721 | 721,1 722 | 722,3 723 | 723,1 724 | 724,4 725 | 725,2 726 | 726,4 727 | 727,2 728 | 728,4 729 | 729,2 730 | 730,4 731 | 731,1 732 | 732,2 733 | 733,2 734 | 734,1 735 | 735,2 736 | 736,3 737 | 737,3 738 | 738,2 739 | 739,4 740 | 740,4 741 | 741,4 742 | 742,2 743 | 743,2 744 | 744,3 745 | 745,1 746 | 746,1 747 | 747,4 748 | 748,1 749 | 749,1 750 | 750,1 751 | 751,4 752 | 752,3 753 | 753,3 754 | 754,2 755 | 755,1 756 | 756,2 757 | 757,3 758 | 758,3 759 | 759,2 760 | 760,1 761 | 761,4 762 | 762,4 763 | 763,3 764 | 764,1 765 | 765,1 766 | 766,3 767 | 767,4 768 | 768,4 769 | 769,2 770 | 770,3 771 | 771,4 772 | 772,4 773 | 773,2 774 | 774,2 775 | 775,2 776 | 776,1 777 | 777,2 778 | 778,2 779 | 779,3 780 | 780,1 781 | 781,3 782 | 782,3 783 | 783,2 784 | 784,3 785 | 785,4 786 | 786,1 787 | 787,4 788 | 788,4 789 | 789,1 790 | 790,1 791 | 791,3 792 | 792,3 793 | 793,4 794 | 794,2 795 | 795,2 796 | 796,4 797 | 797,2 798 | 798,2 799 | 799,1 800 | 800,1 801 | 801,4 802 | 802,1 803 | 803,2 804 | 804,1 805 | 805,2 806 | 806,4 807 | 807,3 808 | 808,2 809 | 809,2 810 | 810,4 811 | 811,3 812 | 812,1 813 | 813,1 814 | 814,3 815 | 815,1 816 | 816,2 817 | 817,3 818 | 818,1 819 | 819,1 820 | 820,1 821 | 821,1 822 | 822,4 823 | 823,3 824 | 824,2 825 | 825,2 826 | 826,4 827 | 827,1 828 | 828,4 829 | 829,4 830 | 830,4 831 | 831,3 832 | 832,4 833 | 833,2 834 | 834,3 835 | 835,2 836 | 836,2 837 | 837,3 838 | 838,3 839 | 839,2 840 | 840,2 841 | 841,1 842 | 842,1 843 | 843,2 844 | 844,3 845 | 845,2 846 | 846,4 847 | 847,3 848 | 848,2 849 | 849,1 850 | 850,1 851 | 851,4 852 | 852,3 853 | 853,4 854 | 854,4 855 | 855,3 856 | 856,2 857 | 857,2 858 | 858,4 859 | 859,3 860 | 860,1 861 | 861,4 862 | 862,2 863 | 863,2 864 | 864,1 865 | 865,3 866 | 866,1 867 | 867,2 868 | 868,3 869 | 869,4 870 | 870,1 871 | 871,3 872 | 872,3 873 | 873,3 874 | 874,1 875 | 875,1 876 | 876,4 877 | 877,3 878 | 878,2 879 | 879,3 880 | 880,3 881 | 881,4 882 | 882,3 883 | 883,1 884 | 884,2 885 | 885,3 886 | 886,2 887 | 887,2 888 | 888,4 889 | 889,3 890 | 890,1 891 | 891,4 892 | 892,2 893 | 893,4 894 | 894,3 895 | 895,3 896 | 896,2 897 | 897,1 898 | 898,1 899 | 899,2 900 | 900,3 901 | 901,2 902 | 902,2 903 | 903,4 904 | 904,1 905 | 905,1 906 | 906,4 907 | 907,1 908 | 908,3 909 | 909,4 910 | 910,1 911 | 911,2 912 | 912,2 913 | 913,4 914 | 914,2 915 | 915,2 916 | 916,2 917 | 917,4 918 | 918,2 919 | 919,1 920 | 920,3 921 | 921,1 922 | 922,2 923 | 923,4 924 | 924,3 925 | 925,2 926 | 926,1 927 | 927,3 928 | 928,1 929 | 929,4 930 | 930,1 931 | 931,3 932 | 932,4 933 | 933,1 934 | 934,2 935 | 935,1 936 | 936,3 937 | 937,3 938 | 938,2 939 | 939,1 940 | 940,3 941 | 941,4 942 | 942,2 943 | 943,2 944 | 944,3 945 | 945,4 946 | 946,3 947 | 947,4 948 | 948,1 949 | 949,3 950 | 950,3 951 | 951,1 952 | 952,1 953 | 953,2 954 | 954,4 955 | 955,3 956 | 956,2 957 | 957,2 958 | 958,2 959 | 959,2 960 | 960,1 961 | 961,4 962 | 962,3 963 | 963,2 964 | 964,3 965 | 965,2 966 | 966,2 967 | 967,3 968 | 968,1 969 | 969,4 970 | 970,2 971 | 971,3 972 | 972,2 973 | 973,1 974 | 974,4 975 | 975,3 976 | 976,4 977 | 977,4 978 | 978,2 979 | 979,4 980 | 980,2 981 | 981,1 982 | 982,3 983 | 983,4 984 | 984,2 985 | 985,1 986 | 986,3 987 | 987,3 988 | 988,1 989 | 989,3 990 | 990,3 991 | 991,4 992 | 992,2 993 | 993,4 994 | 994,3 995 | 995,3 996 | 996,2 997 | 997,1 998 | 998,4 999 | 999,1 1000 | 1000,1 1001 | 1,3 1002 | 2,1 1003 | 3,2 1004 | 4,3 1005 | 5,3 1006 | 6,1 1007 | 7,4 1008 | 8,4 1009 | 9,3 1010 | 10,4 1011 | 11,1 1012 | 12,1 1013 | 13,1 1014 | 14,3 1015 | 15,4 1016 | 16,2 1017 | 17,3 1018 | 18,2 1019 | 19,1 1020 | 20,2 1021 | 21,3 1022 | 22,4 1023 | 23,2 1024 | 24,4 1025 | 25,2 1026 | 26,1 1027 | 27,1 1028 | 28,4 1029 | 29,2 1030 | 30,3 1031 | 31,3 1032 | 32,4 1033 | 33,1 1034 | 34,4 1035 | 35,3 1036 | 36,4 1037 | 37,3 1038 | 38,2 1039 | 39,1 1040 | 40,2 1041 | 41,1 1042 | 42,1 1043 | 43,2 1044 | 44,2 1045 | 45,4 1046 | 46,1 1047 | 47,1 1048 | 48,4 1049 | 49,4 1050 | 50,4 1051 | 51,2 1052 | 52,3 1053 | 53,3 1054 | 54,4 1055 | 55,4 1056 | 56,2 1057 | 57,4 1058 | 58,3 1059 | 59,2 1060 | 60,2 1061 | 61,1 1062 | 62,3 1063 | 63,2 1064 | 64,2 1065 | 65,3 1066 | 66,4 1067 | 67,3 1068 | 68,4 1069 | 69,2 1070 | 70,1 1071 | 71,2 1072 | 72,1 1073 | 73,3 1074 | 74,4 1075 | 75,1 1076 | 76,1 1077 | 77,3 1078 | 78,4 1079 | 79,3 1080 | 80,1 1081 | 81,3 1082 | 82,2 1083 | 83,3 1084 | 84,2 1085 | 85,3 1086 | 86,3 1087 | 87,3 1088 | 88,4 1089 | 89,3 1090 | 90,3 1091 | 91,3 1092 | 92,2 1093 | 93,1 1094 | 94,3 1095 | 95,1 1096 | 96,2 1097 | 97,3 1098 | 98,1 1099 | 99,1 1100 | 100,1 1101 | 101,3 1102 | 102,2 1103 | 103,2 1104 | 104,2 1105 | 105,2 1106 | 106,2 1107 | 107,2 1108 | 108,2 1109 | 109,2 1110 | 110,1 1111 | 111,3 1112 | 112,3 1113 | 113,1 1114 | 114,3 1115 | 115,2 1116 | 116,4 1117 | 117,2 1118 | 118,2 1119 | 119,1 1120 | 120,2 1121 | 121,4 1122 | 122,4 1123 | 123,3 1124 | 124,3 1125 | 125,4 1126 | 126,3 1127 | 127,2 1128 | 128,1 1129 | 129,2 1130 | 130,4 1131 | 131,2 1132 | 132,2 1133 | 133,2 1134 | 134,4 1135 | 135,2 1136 | 136,1 1137 | 137,4 1138 | 138,1 1139 | 139,1 1140 | 140,2 1141 | 141,1 1142 | 142,2 1143 | 143,3 1144 | 144,1 1145 | 145,4 1146 | 146,1 1147 | 147,1 1148 | 148,2 1149 | 149,3 1150 | 150,4 1151 | 151,1 1152 | 152,1 1153 | 153,4 1154 | 154,4 1155 | 155,4 1156 | 156,1 1157 | 157,1 1158 | 158,1 1159 | 159,2 1160 | 160,4 1161 | 161,2 1162 | 162,4 1163 | 163,1 1164 | 164,4 1165 | 165,1 1166 | 166,1 1167 | 167,1 1168 | 168,1 1169 | 169,1 1170 | 170,3 1171 | 171,4 1172 | 172,2 1173 | 173,4 1174 | 174,2 1175 | 175,2 1176 | 176,3 1177 | 177,3 1178 | 178,4 1179 | 179,2 1180 | 180,1 1181 | 181,1 1182 | 182,3 1183 | 183,1 1184 | 184,4 1185 | 185,4 1186 | 186,2 1187 | 187,1 1188 | 188,2 1189 | 189,4 1190 | 190,1 1191 | 191,1 1192 | 192,3 1193 | 193,4 1194 | 194,2 1195 | 195,1 1196 | 196,4 1197 | 197,4 1198 | 198,1 1199 | 199,4 1200 | 200,3 1201 | 201,3 1202 | 202,2 1203 | 203,4 1204 | 204,1 1205 | 205,1 1206 | 206,4 1207 | 207,3 1208 | 208,2 1209 | 209,1 1210 | 210,2 1211 | 211,1 1212 | 212,2 1213 | 213,4 1214 | 214,3 1215 | 215,4 1216 | 216,1 1217 | 217,4 1218 | 218,3 1219 | 219,4 1220 | 220,3 1221 | 221,3 1222 | 222,1 1223 | 223,3 1224 | 224,1 1225 | 225,3 1226 | 226,3 1227 | 227,1 1228 | 228,4 1229 | 229,1 1230 | 230,1 1231 | 231,3 1232 | 232,4 1233 | 233,1 1234 | 234,1 1235 | 235,4 1236 | 236,2 1237 | 237,3 1238 | 238,3 1239 | 239,4 1240 | 240,1 1241 | 241,4 1242 | 242,4 1243 | 243,3 1244 | 244,3 1245 | 245,1 1246 | 246,4 1247 | 247,2 1248 | 248,1 1249 | 249,2 1250 | 250,2 1251 | 251,1 1252 | 252,2 1253 | 253,4 1254 | 254,2 1255 | 255,4 1256 | 256,3 1257 | 257,4 1258 | 258,1 1259 | 259,2 1260 | 260,2 1261 | 261,4 1262 | 262,3 1263 | 263,4 1264 | 264,1 1265 | 265,2 1266 | 266,4 1267 | 267,2 1268 | 268,1 1269 | 269,3 1270 | 270,2 1271 | 271,4 1272 | 272,2 1273 | 273,1 1274 | 274,4 1275 | 275,3 1276 | 276,2 1277 | 277,2 1278 | 278,4 1279 | 279,2 1280 | 280,4 1281 | 281,4 1282 | 282,4 1283 | 283,2 1284 | 284,2 1285 | 285,4 1286 | 286,1 1287 | 287,4 1288 | 288,2 1289 | 289,2 1290 | 290,1 1291 | 291,4 1292 | 292,1 1293 | 293,4 1294 | 294,1 1295 | 295,4 1296 | 296,3 1297 | 297,2 1298 | 298,3 1299 | 299,3 1300 | 300,3 1301 | 301,4 1302 | 302,4 1303 | 303,1 1304 | 304,4 1305 | 305,2 1306 | 306,3 1307 | 307,4 1308 | 308,4 1309 | 309,4 1310 | 310,2 1311 | 311,3 1312 | 312,4 1313 | 313,4 1314 | 314,2 1315 | 315,4 1316 | 316,1 1317 | 317,1 1318 | 318,1 1319 | 319,4 1320 | 320,4 1321 | 321,1 1322 | 322,4 1323 | 323,4 1324 | 324,3 1325 | 325,1 1326 | 326,1 1327 | 327,3 1328 | 328,1 1329 | 329,4 1330 | 330,2 1331 | 331,1 1332 | 332,4 1333 | 333,4 1334 | 334,1 1335 | 335,1 1336 | 336,1 1337 | 337,4 1338 | 338,1 1339 | 339,4 1340 | 340,1 1341 | 341,4 1342 | 342,4 1343 | 343,1 1344 | 344,2 1345 | 345,2 1346 | 346,2 1347 | 347,3 1348 | 348,3 1349 | 349,1 1350 | 350,4 1351 | 351,2 1352 | 352,2 1353 | 353,1 1354 | 354,2 1355 | 355,1 1356 | 356,1 1357 | 357,1 1358 | 358,1 1359 | 359,1 1360 | 360,3 1361 | 361,3 1362 | 362,1 1363 | 363,1 1364 | 364,1 1365 | 365,3 1366 | 366,2 1367 | 367,3 1368 | 368,4 1369 | 369,3 1370 | 370,3 1371 | 371,2 1372 | 372,4 1373 | 373,3 1374 | 374,2 1375 | 375,1 1376 | 376,1 1377 | 377,1 1378 | 378,2 1379 | 379,4 1380 | 380,1 1381 | 381,4 1382 | 382,2 1383 | 383,3 1384 | 384,4 1385 | 385,3 1386 | 386,4 1387 | 387,1 1388 | 388,2 1389 | 389,2 1390 | 390,3 1391 | 391,3 1392 | 392,3 1393 | 393,1 1394 | 394,2 1395 | 395,4 1396 | 396,4 1397 | 397,1 1398 | 398,1 1399 | 399,3 1400 | 400,3 1401 | 401,1 1402 | 402,1 1403 | 403,3 1404 | 404,4 1405 | 405,3 1406 | 406,2 1407 | 407,2 1408 | 408,4 1409 | 409,3 1410 | 410,2 1411 | 411,3 1412 | 412,3 1413 | 413,4 1414 | 414,3 1415 | 415,2 1416 | 416,2 1417 | 417,2 1418 | 418,4 1419 | 419,1 1420 | 420,1 1421 | 421,2 1422 | 422,4 1423 | 423,4 1424 | 424,1 1425 | 425,1 1426 | 426,4 1427 | 427,2 1428 | 428,2 1429 | 429,4 1430 | 430,2 1431 | 431,2 1432 | 432,1 1433 | 433,4 1434 | 434,2 1435 | 435,2 1436 | 436,2 1437 | 437,1 1438 | 438,1 1439 | 439,1 1440 | 440,2 1441 | 441,1 1442 | 442,3 1443 | 443,3 1444 | 444,3 1445 | 445,4 1446 | 446,4 1447 | 447,3 1448 | 448,2 1449 | 449,1 1450 | 450,3 1451 | 451,1 1452 | 452,1 1453 | 453,2 1454 | 454,1 1455 | 455,3 1456 | 456,4 1457 | 457,1 1458 | 458,4 1459 | 459,2 1460 | 460,2 1461 | 461,4 1462 | 462,3 1463 | 463,3 1464 | 464,3 1465 | 465,2 1466 | 466,1 1467 | 467,4 1468 | 468,4 1469 | 469,2 1470 | 470,2 1471 | 471,2 1472 | 472,4 1473 | 473,2 1474 | 474,4 1475 | 475,2 1476 | 476,3 1477 | 477,1 1478 | 478,4 1479 | 479,4 1480 | 480,3 1481 | 481,1 1482 | 482,1 1483 | 483,3 1484 | 484,3 1485 | 485,3 1486 | 486,1 1487 | 487,3 1488 | 488,4 1489 | 489,2 1490 | 490,2 1491 | 491,2 1492 | 492,2 1493 | 493,1 1494 | 494,3 1495 | 495,3 1496 | 496,3 1497 | 497,4 1498 | 498,4 1499 | 499,3 1500 | 500,3 1501 | 501,4 1502 | 502,2 1503 | 503,1 1504 | 504,3 1505 | 505,1 1506 | 506,3 1507 | 507,4 1508 | 508,4 1509 | 509,4 1510 | 510,4 1511 | 511,4 1512 | 512,3 1513 | 513,1 1514 | 514,1 1515 | 515,3 1516 | 516,4 1517 | 517,1 1518 | 518,2 1519 | 519,2 1520 | 520,3 1521 | 521,1 1522 | 522,1 1523 | 523,1 1524 | 524,3 1525 | 525,3 1526 | 526,3 1527 | 527,4 1528 | 528,4 1529 | 529,2 1530 | 530,2 1531 | 531,4 1532 | 532,2 1533 | 533,1 1534 | 534,2 1535 | 535,2 1536 | 536,1 1537 | 537,1 1538 | 538,3 1539 | 539,1 1540 | 540,1 1541 | 541,1 1542 | 542,1 1543 | 543,1 1544 | 544,1 1545 | 545,1 1546 | 546,3 1547 | 547,4 1548 | 548,1 1549 | 549,1 1550 | 550,4 1551 | 551,1 1552 | 552,1 1553 | 553,4 1554 | 554,1 1555 | 555,4 1556 | 556,3 1557 | 557,4 1558 | 558,3 1559 | 559,3 1560 | 560,4 1561 | 561,2 1562 | 562,4 1563 | 563,1 1564 | 564,3 1565 | 565,3 1566 | 566,3 1567 | 567,2 1568 | 568,4 1569 | 569,2 1570 | 570,4 1571 | 571,4 1572 | 572,1 1573 | 573,3 1574 | 574,2 1575 | 575,4 1576 | 576,3 1577 | 577,2 1578 | 578,3 1579 | 579,1 1580 | 580,3 1581 | 581,4 1582 | 582,1 1583 | 583,1 1584 | 584,3 1585 | 585,4 1586 | 586,2 1587 | 587,1 1588 | 588,4 1589 | 589,3 1590 | 590,3 1591 | 591,1 1592 | 592,3 1593 | 593,1 1594 | 594,1 1595 | 595,2 1596 | 596,4 1597 | 597,3 1598 | 598,4 1599 | 599,2 1600 | 600,3 1601 | 601,2 1602 | 602,1 1603 | 603,3 1604 | 604,3 1605 | 605,2 1606 | 606,1 1607 | 607,3 1608 | 608,4 1609 | 609,4 1610 | 610,2 1611 | 611,2 1612 | 612,3 1613 | 613,4 1614 | 614,3 1615 | 615,4 1616 | 616,3 1617 | 617,2 1618 | 618,1 1619 | 619,4 1620 | 620,4 1621 | 621,1 1622 | 622,1 1623 | 623,1 1624 | 624,3 1625 | 625,2 1626 | 626,2 1627 | 627,4 1628 | 628,2 1629 | 629,1 1630 | 630,4 1631 | 631,3 1632 | 632,3 1633 | 633,4 1634 | 634,1 1635 | 635,1 1636 | 636,1 1637 | 637,3 1638 | 638,2 1639 | 639,2 1640 | 640,3 1641 | 641,2 1642 | 642,4 1643 | 643,2 1644 | 644,1 1645 | 645,2 1646 | 646,1 1647 | 647,3 1648 | 648,1 1649 | 649,3 1650 | 650,1 1651 | 651,3 1652 | 652,2 1653 | 653,1 1654 | 654,4 1655 | 655,3 1656 | 656,1 1657 | 657,3 1658 | 658,3 1659 | 659,1 1660 | 660,2 1661 | 661,1 1662 | 662,1 1663 | 663,1 1664 | 664,2 1665 | 665,2 1666 | 666,3 1667 | 667,1 1668 | 668,2 1669 | 669,1 1670 | 670,4 1671 | 671,2 1672 | 672,3 1673 | 673,3 1674 | 674,2 1675 | 675,4 1676 | 676,3 1677 | 677,3 1678 | 678,2 1679 | 679,4 1680 | 680,2 1681 | 681,2 1682 | 682,2 1683 | 683,1 1684 | 684,1 1685 | 685,1 1686 | 686,3 1687 | 687,3 1688 | 688,2 1689 | 689,1 1690 | 690,4 1691 | 691,4 1692 | 692,3 1693 | 693,4 1694 | 694,3 1695 | 695,2 1696 | 696,2 1697 | 697,4 1698 | 698,2 1699 | 699,2 1700 | 700,4 1701 | 701,4 1702 | 702,1 1703 | 703,3 1704 | 704,1 1705 | 705,4 1706 | 706,2 1707 | 707,1 1708 | 708,1 1709 | 709,2 1710 | 710,2 1711 | 711,4 1712 | 712,4 1713 | 713,2 1714 | 714,4 1715 | 715,1 1716 | 716,1 1717 | 717,4 1718 | 718,1 1719 | 719,3 1720 | 720,3 1721 | 721,2 1722 | 722,4 1723 | 723,1 1724 | 724,2 1725 | 725,3 1726 | 726,3 1727 | 727,3 1728 | 728,3 1729 | 729,3 1730 | 730,2 1731 | 731,2 1732 | 732,3 1733 | 733,3 1734 | 734,4 1735 | 735,1 1736 | 736,2 1737 | 737,2 1738 | 738,4 1739 | 739,4 1740 | 740,2 1741 | 741,4 1742 | 742,2 1743 | 743,3 1744 | 744,2 1745 | 745,2 1746 | 746,1 1747 | 747,1 1748 | 748,2 1749 | 749,1 1750 | 750,1 1751 | 751,2 1752 | 752,3 1753 | 753,4 1754 | 754,2 1755 | 755,1 1756 | 756,3 1757 | 757,2 1758 | 758,2 1759 | 759,3 1760 | 760,2 1761 | 761,1 1762 | 762,2 1763 | 763,3 1764 | 764,2 1765 | 765,4 1766 | 766,3 1767 | 767,2 1768 | 768,2 1769 | 769,2 1770 | 770,3 1771 | 771,1 1772 | 772,4 1773 | 773,4 1774 | 774,1 1775 | 775,4 1776 | 776,3 1777 | 777,3 1778 | 778,1 1779 | 779,3 1780 | 780,4 1781 | 781,2 1782 | 782,2 1783 | 783,4 1784 | 784,3 1785 | 785,2 1786 | 786,4 1787 | 787,1 1788 | 788,4 1789 | 789,4 1790 | 790,2 1791 | 791,2 1792 | 792,2 1793 | 793,4 1794 | 794,1 1795 | 795,3 1796 | 796,3 1797 | 797,1 1798 | 798,1 1799 | 799,4 1800 | 800,2 1801 | 801,2 1802 | 802,2 1803 | 803,3 1804 | 804,2 1805 | 805,4 1806 | 806,3 1807 | 807,2 1808 | 808,3 1809 | 809,1 1810 | 810,1 1811 | 811,3 1812 | 812,2 1813 | 813,2 1814 | 814,1 1815 | 815,4 1816 | 816,4 1817 | 817,2 1818 | 818,2 1819 | 819,3 1820 | 820,1 1821 | 821,4 1822 | 822,3 1823 | 823,3 1824 | 824,1 1825 | 825,3 1826 | 826,1 1827 | 827,1 1828 | 828,4 1829 | 829,1 1830 | 830,3 1831 | 831,2 1832 | 832,4 1833 | 833,3 1834 | 834,1 1835 | 835,2 1836 | 836,3 1837 | 837,4 1838 | 838,2 1839 | 839,1 1840 | 840,4 1841 | 841,1 1842 | 842,3 1843 | 843,3 1844 | 844,2 1845 | 845,3 1846 | 846,3 1847 | 847,2 1848 | 848,1 1849 | 849,3 1850 | 850,3 1851 | 851,3 1852 | 852,1 1853 | 853,1 1854 | 854,2 1855 | 855,1 1856 | 856,1 1857 | 857,1 1858 | 858,1 1859 | 859,1 1860 | 860,1 1861 | 861,4 1862 | 862,1 1863 | 863,3 1864 | 864,3 1865 | 865,1 1866 | 866,3 1867 | 867,3 1868 | 868,1 1869 | 869,3 1870 | 870,4 1871 | 871,4 1872 | 872,3 1873 | 873,2 1874 | 874,2 1875 | 875,2 1876 | 876,3 1877 | 877,1 1878 | 878,2 1879 | 879,1 1880 | 880,1 1881 | 881,4 1882 | 882,3 1883 | 883,3 1884 | 884,1 1885 | 885,3 1886 | 886,3 1887 | 887,2 1888 | 888,4 1889 | 889,4 1890 | 890,3 1891 | 891,2 1892 | 892,2 1893 | 893,2 1894 | 894,3 1895 | 895,4 1896 | 896,1 1897 | 897,1 1898 | 898,3 1899 | 899,3 1900 | 900,2 1901 | 901,3 1902 | 902,3 1903 | 903,3 1904 | 904,1 1905 | 905,2 1906 | 906,3 1907 | 907,4 1908 | 908,3 1909 | 909,4 1910 | 910,4 1911 | 911,4 1912 | 912,2 1913 | 913,1 1914 | 914,2 1915 | 915,1 1916 | 916,3 1917 | 917,4 1918 | 918,4 1919 | 919,3 1920 | 920,2 1921 | 921,1 1922 | 922,2 1923 | 923,4 1924 | 924,3 1925 | 925,2 1926 | 926,3 1927 | 927,2 1928 | 928,2 1929 | 929,4 1930 | 930,3 1931 | 931,4 1932 | 932,4 1933 | 933,3 1934 | 934,2 1935 | 935,4 1936 | 936,4 1937 | 937,2 1938 | 938,4 1939 | 939,1 1940 | 940,4 1941 | 941,2 1942 | 942,1 1943 | 943,1 1944 | 944,3 1945 | 945,3 1946 | 946,2 1947 | 947,4 1948 | 948,4 1949 | 949,2 1950 | 950,3 1951 | 951,3 1952 | 952,2 1953 | 953,2 1954 | 954,1 1955 | 955,1 1956 | 956,1 1957 | 957,1 1958 | 958,1 1959 | 959,2 1960 | 960,3 1961 | 961,2 1962 | 962,2 1963 | 963,4 1964 | 964,3 1965 | 965,2 1966 | 966,3 1967 | 967,3 1968 | 968,2 1969 | 969,4 1970 | 970,4 1971 | 971,1 1972 | 972,1 1973 | 973,4 1974 | 974,4 1975 | 975,4 1976 | 976,3 1977 | 977,2 1978 | 978,2 1979 | 979,1 1980 | 980,2 1981 | 981,4 1982 | 982,4 1983 | 983,1 1984 | 984,2 1985 | 985,1 1986 | 986,2 1987 | 987,4 1988 | 988,2 1989 | 989,1 1990 | 990,3 1991 | 991,2 1992 | 992,2 1993 | 993,1 1994 | 994,4 1995 | 995,4 1996 | 996,3 1997 | 997,3 1998 | 998,2 1999 | 999,2 2000 | 1000,4 2001 | 1,1 2002 | 2,1 2003 | 3,2 2004 | 4,4 2005 | 5,2 2006 | 6,2 2007 | 7,1 2008 | 8,3 2009 | 9,2 2010 | 10,3 2011 | 11,2 2012 | 12,3 2013 | 13,1 2014 | 14,2 2015 | 15,2 2016 | 16,4 2017 | 17,2 2018 | 18,3 2019 | 19,4 2020 | 20,1 2021 | 21,3 2022 | 22,2 2023 | 23,4 2024 | 24,4 2025 | 25,2 2026 | 26,4 2027 | 27,4 2028 | 28,2 2029 | 29,1 2030 | 30,3 2031 | 31,1 2032 | 32,2 2033 | 33,4 2034 | 34,1 2035 | 35,2 2036 | 36,4 2037 | 37,3 2038 | 38,4 2039 | 39,4 2040 | 40,2 2041 | 41,4 2042 | 42,3 2043 | 43,2 2044 | 44,3 2045 | 45,2 2046 | 46,3 2047 | 47,3 2048 | 48,3 2049 | 49,2 2050 | 50,4 2051 | 51,4 2052 | 52,3 2053 | 53,2 2054 | 54,4 2055 | 55,4 2056 | 56,1 2057 | 57,2 2058 | 58,1 2059 | 59,4 2060 | 60,1 2061 | 61,3 2062 | 62,1 2063 | 63,2 2064 | 64,2 2065 | 65,1 2066 | 66,2 2067 | 67,2 2068 | 68,1 2069 | 69,3 2070 | 70,3 2071 | 71,4 2072 | 72,1 2073 | 73,3 2074 | 74,3 2075 | 75,3 2076 | 76,4 2077 | 77,2 2078 | 78,1 2079 | 79,4 2080 | 80,3 2081 | 81,4 2082 | 82,3 2083 | 83,2 2084 | 84,4 2085 | 85,2 2086 | 86,2 2087 | 87,4 2088 | 88,4 2089 | 89,1 2090 | 90,3 2091 | 91,2 2092 | 92,2 2093 | 93,4 2094 | 94,3 2095 | 95,3 2096 | 96,2 2097 | 97,1 2098 | 98,3 2099 | 99,4 2100 | 100,3 2101 | 101,1 2102 | 102,3 2103 | 103,1 2104 | 104,1 2105 | 105,4 2106 | 106,4 2107 | 107,3 2108 | 108,3 2109 | 109,1 2110 | 110,2 2111 | 111,2 2112 | 112,4 2113 | 113,2 2114 | 114,4 2115 | 115,1 2116 | 116,4 2117 | 117,1 2118 | 118,1 2119 | 119,1 2120 | 120,4 2121 | 121,2 2122 | 122,3 2123 | 123,1 2124 | 124,2 2125 | 125,4 2126 | 126,1 2127 | 127,2 2128 | 128,2 2129 | 129,1 2130 | 130,2 2131 | 131,3 2132 | 132,2 2133 | 133,3 2134 | 134,4 2135 | 135,2 2136 | 136,1 2137 | 137,2 2138 | 138,4 2139 | 139,3 2140 | 140,3 2141 | 141,2 2142 | 142,1 2143 | 143,2 2144 | 144,1 2145 | 145,2 2146 | 146,1 2147 | 147,3 2148 | 148,2 2149 | 149,2 2150 | 150,1 2151 | 151,1 2152 | 152,3 2153 | 153,2 2154 | 154,1 2155 | 155,4 2156 | 156,3 2157 | 157,2 2158 | 158,4 2159 | 159,2 2160 | 160,2 2161 | 161,3 2162 | 162,1 2163 | 163,2 2164 | 164,4 2165 | 165,4 2166 | 166,3 2167 | 167,3 2168 | 168,4 2169 | 169,1 2170 | 170,3 2171 | 171,4 2172 | 172,3 2173 | 173,3 2174 | 174,1 2175 | 175,2 2176 | 176,3 2177 | 177,2 2178 | 178,1 2179 | 179,1 2180 | 180,3 2181 | 181,4 2182 | 182,4 2183 | 183,1 2184 | 184,1 2185 | 185,2 2186 | 186,4 2187 | 187,2 2188 | 188,4 2189 | 189,1 2190 | 190,4 2191 | 191,2 2192 | 192,3 2193 | 193,1 2194 | 194,4 2195 | 195,1 2196 | 196,4 2197 | 197,4 2198 | 198,3 2199 | 199,4 2200 | 200,4 2201 | 201,1 2202 | 202,1 2203 | 203,1 2204 | 204,2 2205 | 205,2 2206 | 206,4 2207 | 207,1 2208 | 208,3 2209 | 209,3 2210 | 210,1 2211 | 211,1 2212 | 212,4 2213 | 213,4 2214 | 214,1 2215 | 215,2 2216 | 216,1 2217 | 217,4 2218 | 218,2 2219 | 219,3 2220 | 220,3 2221 | 221,1 2222 | 222,3 2223 | 223,1 2224 | 224,2 2225 | 225,1 2226 | 226,4 2227 | 227,2 2228 | 228,2 2229 | 229,2 2230 | 230,3 2231 | 231,3 2232 | 232,2 2233 | 233,2 2234 | 234,2 2235 | 235,1 2236 | 236,3 2237 | 237,2 2238 | 238,2 2239 | 239,1 2240 | 240,2 2241 | 241,4 2242 | 242,1 2243 | 243,1 2244 | 244,1 2245 | 245,3 2246 | 246,4 2247 | 247,4 2248 | 248,1 2249 | 249,3 2250 | 250,1 2251 | 251,2 2252 | 252,4 2253 | 253,2 2254 | 254,1 2255 | 255,4 2256 | 256,2 2257 | 257,2 2258 | 258,3 2259 | 259,3 2260 | 260,4 2261 | 261,3 2262 | 262,3 2263 | 263,1 2264 | 264,4 2265 | 265,1 2266 | 266,3 2267 | 267,4 2268 | 268,1 2269 | 269,3 2270 | 270,2 2271 | 271,3 2272 | 272,2 2273 | 273,2 2274 | 274,2 2275 | 275,1 2276 | 276,1 2277 | 277,4 2278 | 278,3 2279 | 279,2 2280 | 280,3 2281 | 281,2 2282 | 282,3 2283 | 283,4 2284 | 284,3 2285 | 285,2 2286 | 286,3 2287 | 287,4 2288 | 288,1 2289 | 289,3 2290 | 290,2 2291 | 291,2 2292 | 292,3 2293 | 293,4 2294 | 294,4 2295 | 295,3 2296 | 296,3 2297 | 297,2 2298 | 298,4 2299 | 299,2 2300 | 300,4 2301 | 301,1 2302 | 302,1 2303 | 303,2 2304 | 304,1 2305 | 305,2 2306 | 306,1 2307 | 307,2 2308 | 308,2 2309 | 309,4 2310 | 310,1 2311 | 311,3 2312 | 312,1 2313 | 313,3 2314 | 314,1 2315 | 315,2 2316 | 316,2 2317 | 317,3 2318 | 318,2 2319 | 319,1 2320 | 320,1 2321 | 321,3 2322 | 322,1 2323 | 323,4 2324 | 324,3 2325 | 325,2 2326 | 326,2 2327 | 327,4 2328 | 328,3 2329 | 329,3 2330 | 330,2 2331 | 331,1 2332 | 332,4 2333 | 333,3 2334 | 334,4 2335 | 335,2 2336 | 336,2 2337 | 337,4 2338 | 338,3 2339 | 339,1 2340 | 340,3 2341 | 341,4 2342 | 342,4 2343 | 343,2 2344 | 344,1 2345 | 345,4 2346 | 346,1 2347 | 347,1 2348 | 348,1 2349 | 349,1 2350 | 350,2 2351 | 351,4 2352 | 352,2 2353 | 353,4 2354 | 354,3 2355 | 355,1 2356 | 356,4 2357 | 357,3 2358 | 358,4 2359 | 359,4 2360 | 360,3 2361 | 361,2 2362 | 362,3 2363 | 363,4 2364 | 364,4 2365 | 365,2 2366 | 366,1 2367 | 367,3 2368 | 368,3 2369 | 369,2 2370 | 370,3 2371 | 371,1 2372 | 372,2 2373 | 373,2 2374 | 374,3 2375 | 375,4 2376 | 376,2 2377 | 377,1 2378 | 378,3 2379 | 379,2 2380 | 380,2 2381 | 381,3 2382 | 382,1 2383 | 383,3 2384 | 384,1 2385 | 385,3 2386 | 386,4 2387 | 387,3 2388 | 388,3 2389 | 389,2 2390 | 390,1 2391 | 391,4 2392 | 392,2 2393 | 393,3 2394 | 394,4 2395 | 395,3 2396 | 396,1 2397 | 397,4 2398 | 398,2 2399 | 399,4 2400 | 400,1 2401 | 401,1 2402 | 402,1 2403 | 403,4 2404 | 404,4 2405 | 405,3 2406 | 406,2 2407 | 407,1 2408 | 408,3 2409 | 409,2 2410 | 410,2 2411 | 411,3 2412 | 412,2 2413 | 413,2 2414 | 414,1 2415 | 415,4 2416 | 416,3 2417 | 417,1 2418 | 418,3 2419 | 419,2 2420 | 420,4 2421 | 421,1 2422 | 422,2 2423 | 423,4 2424 | 424,3 2425 | 425,2 2426 | 426,1 2427 | 427,4 2428 | 428,2 2429 | 429,1 2430 | 430,2 2431 | 431,2 2432 | 432,4 2433 | 433,1 2434 | 434,4 2435 | 435,4 2436 | 436,3 2437 | 437,1 2438 | 438,3 2439 | 439,4 2440 | 440,2 2441 | 441,3 2442 | 442,4 2443 | 443,2 2444 | 444,4 2445 | 445,1 2446 | 446,4 2447 | 447,4 2448 | 448,3 2449 | 449,2 2450 | 450,3 2451 | 451,3 2452 | 452,4 2453 | 453,3 2454 | 454,4 2455 | 455,4 2456 | 456,4 2457 | 457,4 2458 | 458,4 2459 | 459,2 2460 | 460,2 2461 | 461,1 2462 | 462,2 2463 | 463,3 2464 | 464,3 2465 | 465,3 2466 | 466,1 2467 | 467,1 2468 | 468,4 2469 | 469,3 2470 | 470,4 2471 | 471,2 2472 | 472,2 2473 | 473,1 2474 | 474,1 2475 | 475,1 2476 | 476,4 2477 | 477,4 2478 | 478,4 2479 | 479,2 2480 | 480,1 2481 | 481,3 2482 | 482,2 2483 | 483,2 2484 | 484,1 2485 | 485,4 2486 | 486,2 2487 | 487,3 2488 | 488,4 2489 | 489,1 2490 | 490,3 2491 | 491,2 2492 | 492,3 2493 | 493,2 2494 | 494,1 2495 | 495,2 2496 | 496,3 2497 | 497,1 2498 | 498,2 2499 | 499,1 2500 | 500,3 2501 | 501,4 2502 | 502,1 2503 | 503,1 2504 | 504,3 2505 | 505,4 2506 | 506,3 2507 | 507,3 2508 | 508,1 2509 | 509,1 2510 | 510,2 2511 | 511,4 2512 | 512,1 2513 | 513,4 2514 | 514,4 2515 | 515,4 2516 | 516,1 2517 | 517,2 2518 | 518,1 2519 | 519,3 2520 | 520,1 2521 | 521,1 2522 | 522,2 2523 | 523,4 2524 | 524,2 2525 | 525,3 2526 | 526,4 2527 | 527,3 2528 | 528,2 2529 | 529,1 2530 | 530,1 2531 | 531,4 2532 | 532,2 2533 | 533,2 2534 | 534,1 2535 | 535,3 2536 | 536,2 2537 | 537,1 2538 | 538,2 2539 | 539,2 2540 | 540,1 2541 | 541,2 2542 | 542,2 2543 | 543,2 2544 | 544,4 2545 | 545,3 2546 | 546,1 2547 | 547,4 2548 | 548,1 2549 | 549,2 2550 | 550,2 2551 | 551,4 2552 | 552,1 2553 | 553,3 2554 | 554,2 2555 | 555,2 2556 | 556,2 2557 | 557,1 2558 | 558,2 2559 | 559,1 2560 | 560,4 2561 | 561,1 2562 | 562,2 2563 | 563,2 2564 | 564,3 2565 | 565,2 2566 | 566,1 2567 | 567,4 2568 | 568,3 2569 | 569,3 2570 | 570,2 2571 | 571,1 2572 | 572,3 2573 | 573,2 2574 | 574,1 2575 | 575,1 2576 | 576,3 2577 | 577,2 2578 | 578,4 2579 | 579,3 2580 | 580,3 2581 | 581,3 2582 | 582,4 2583 | 583,3 2584 | 584,3 2585 | 585,2 2586 | 586,2 2587 | 587,3 2588 | 588,1 2589 | 589,4 2590 | 590,3 2591 | 591,1 2592 | 592,1 2593 | 593,2 2594 | 594,2 2595 | 595,3 2596 | 596,2 2597 | 597,3 2598 | 598,4 2599 | 599,2 2600 | 600,3 2601 | 601,3 2602 | 602,1 2603 | 603,2 2604 | 604,1 2605 | 605,3 2606 | 606,2 2607 | 607,1 2608 | 608,3 2609 | 609,2 2610 | 610,4 2611 | 611,2 2612 | 612,3 2613 | 613,4 2614 | 614,2 2615 | 615,3 2616 | 616,3 2617 | 617,1 2618 | 618,2 2619 | 619,4 2620 | 620,1 2621 | 621,3 2622 | 622,3 2623 | 623,3 2624 | 624,3 2625 | 625,1 2626 | 626,1 2627 | 627,3 2628 | 628,1 2629 | 629,2 2630 | 630,2 2631 | 631,4 2632 | 632,4 2633 | 633,2 2634 | 634,4 2635 | 635,2 2636 | 636,4 2637 | 637,2 2638 | 638,3 2639 | 639,3 2640 | 640,4 2641 | 641,3 2642 | 642,3 2643 | 643,1 2644 | 644,3 2645 | 645,1 2646 | 646,4 2647 | 647,3 2648 | 648,2 2649 | 649,1 2650 | 650,1 2651 | 651,2 2652 | 652,2 2653 | 653,1 2654 | 654,2 2655 | 655,4 2656 | 656,1 2657 | 657,2 2658 | 658,1 2659 | 659,1 2660 | 660,4 2661 | 661,1 2662 | 662,1 2663 | 663,1 2664 | 664,3 2665 | 665,4 2666 | 666,3 2667 | 667,4 2668 | 668,1 2669 | 669,2 2670 | 670,3 2671 | 671,2 2672 | 672,4 2673 | 673,4 2674 | 674,1 2675 | 675,1 2676 | 676,4 2677 | 677,2 2678 | 678,4 2679 | 679,4 2680 | 680,4 2681 | 681,3 2682 | 682,2 2683 | 683,1 2684 | 684,4 2685 | 685,4 2686 | 686,1 2687 | 687,4 2688 | 688,3 2689 | 689,2 2690 | 690,1 2691 | 691,2 2692 | 692,3 2693 | 693,1 2694 | 694,1 2695 | 695,2 2696 | 696,3 2697 | 697,1 2698 | 698,2 2699 | 699,1 2700 | 700,3 2701 | 701,4 2702 | 702,3 2703 | 703,4 2704 | 704,4 2705 | 705,3 2706 | 706,3 2707 | 707,2 2708 | 708,2 2709 | 709,2 2710 | 710,4 2711 | 711,1 2712 | 712,1 2713 | 713,1 2714 | 714,2 2715 | 715,4 2716 | 716,1 2717 | 717,1 2718 | 718,3 2719 | 719,1 2720 | 720,2 2721 | 721,3 2722 | 722,1 2723 | 723,4 2724 | 724,2 2725 | 725,2 2726 | 726,2 2727 | 727,2 2728 | 728,4 2729 | 729,3 2730 | 730,4 2731 | 731,2 2732 | 732,3 2733 | 733,4 2734 | 734,2 2735 | 735,4 2736 | 736,3 2737 | 737,1 2738 | 738,3 2739 | 739,2 2740 | 740,3 2741 | 741,2 2742 | 742,2 2743 | 743,1 2744 | 744,3 2745 | 745,3 2746 | 746,1 2747 | 747,4 2748 | 748,3 2749 | 749,3 2750 | 750,3 2751 | 751,1 2752 | 752,3 2753 | 753,3 2754 | 754,2 2755 | 755,3 2756 | 756,4 2757 | 757,2 2758 | 758,1 2759 | 759,2 2760 | 760,4 2761 | 761,1 2762 | 762,2 2763 | 763,2 2764 | 764,1 2765 | 765,4 2766 | 766,1 2767 | 767,3 2768 | 768,2 2769 | 769,1 2770 | 770,2 2771 | 771,3 2772 | 772,2 2773 | 773,2 2774 | 774,4 2775 | 775,4 2776 | 776,3 2777 | 777,4 2778 | 778,1 2779 | 779,1 2780 | 780,3 2781 | 781,2 2782 | 782,4 2783 | 783,1 2784 | 784,3 2785 | 785,2 2786 | 786,4 2787 | 787,1 2788 | 788,1 2789 | 789,1 2790 | 790,1 2791 | 791,1 2792 | 792,2 2793 | 793,3 2794 | 794,2 2795 | 795,4 2796 | 796,2 2797 | 797,2 2798 | 798,1 2799 | 799,3 2800 | 800,1 2801 | 801,4 2802 | 802,4 2803 | 803,1 2804 | 804,1 2805 | 805,4 2806 | 806,4 2807 | 807,2 2808 | 808,1 2809 | 809,2 2810 | 810,4 2811 | 811,4 2812 | 812,1 2813 | 813,4 2814 | 814,2 2815 | 815,2 2816 | 816,2 2817 | 817,4 2818 | 818,4 2819 | 819,3 2820 | 820,1 2821 | 821,3 2822 | 822,4 2823 | 823,4 2824 | 824,4 2825 | 825,4 2826 | 826,2 2827 | 827,3 2828 | 828,2 2829 | 829,2 2830 | 830,2 2831 | 831,2 2832 | 832,4 2833 | 833,4 2834 | 834,1 2835 | 835,3 2836 | 836,3 2837 | 837,4 2838 | 838,4 2839 | 839,3 2840 | 840,1 2841 | 841,4 2842 | 842,2 2843 | 843,1 2844 | 844,4 2845 | 845,4 2846 | 846,4 2847 | 847,3 2848 | 848,1 2849 | 849,2 2850 | 850,2 2851 | 851,1 2852 | 852,1 2853 | 853,1 2854 | 854,4 2855 | 855,4 2856 | 856,4 2857 | 857,2 2858 | 858,2 2859 | 859,2 2860 | 860,3 2861 | 861,1 2862 | 862,3 2863 | 863,2 2864 | 864,3 2865 | 865,3 2866 | 866,4 2867 | 867,4 2868 | 868,1 2869 | 869,3 2870 | 870,4 2871 | 871,3 2872 | 872,3 2873 | 873,1 2874 | 874,3 2875 | 875,3 2876 | 876,3 2877 | 877,1 2878 | 878,3 2879 | 879,3 2880 | 880,2 2881 | 881,1 2882 | 882,1 2883 | 883,1 2884 | 884,2 2885 | 885,4 2886 | 886,4 2887 | 887,1 2888 | 888,1 2889 | 889,3 2890 | 890,3 2891 | 891,4 2892 | 892,2 2893 | 893,1 2894 | 894,4 2895 | 895,2 2896 | 896,3 2897 | 897,1 2898 | 898,3 2899 | 899,2 2900 | 900,1 2901 | 901,3 2902 | 902,1 2903 | 903,3 2904 | 904,1 2905 | 905,4 2906 | 906,4 2907 | 907,2 2908 | 908,3 2909 | 909,1 2910 | 910,2 2911 | 911,1 2912 | 912,3 2913 | 913,2 2914 | 914,2 2915 | 915,4 2916 | 916,4 2917 | 917,1 2918 | 918,2 2919 | 919,2 2920 | 920,4 2921 | 921,1 2922 | 922,4 2923 | 923,1 2924 | 924,3 2925 | 925,1 2926 | 926,2 2927 | 927,1 2928 | 928,2 2929 | 929,1 2930 | 930,2 2931 | 931,4 2932 | 932,2 2933 | 933,1 2934 | 934,3 2935 | 935,3 2936 | 936,4 2937 | 937,4 2938 | 938,2 2939 | 939,2 2940 | 940,4 2941 | 941,2 2942 | 942,2 2943 | 943,3 2944 | 944,3 2945 | 945,4 2946 | 946,1 2947 | 947,3 2948 | 948,3 2949 | 949,2 2950 | 950,2 2951 | 951,4 2952 | 952,3 2953 | 953,3 2954 | 954,3 2955 | 955,2 2956 | 956,1 2957 | 957,3 2958 | 958,2 2959 | 959,3 2960 | 960,3 2961 | 961,4 2962 | 962,1 2963 | 963,1 2964 | 964,2 2965 | 965,4 2966 | 966,1 2967 | 967,1 2968 | 968,1 2969 | 969,1 2970 | 970,3 2971 | 971,1 2972 | 972,4 2973 | 973,1 2974 | 974,1 2975 | 975,2 2976 | 976,3 2977 | 977,2 2978 | 978,1 2979 | 979,2 2980 | 980,3 2981 | 981,2 2982 | 982,4 2983 | 983,1 2984 | 984,3 2985 | 985,2 2986 | 986,2 2987 | 987,1 2988 | 988,4 2989 | 989,4 2990 | 990,1 2991 | 991,3 2992 | 992,1 2993 | 993,4 2994 | 994,2 2995 | 995,4 2996 | 996,1 2997 | 997,4 2998 | 998,2 2999 | 999,1 3000 | 1000,2 3001 | -------------------------------------------------------------------------------- /src/main/resources/jmeter/seckill.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Content-Type 18 | application/json 19 | 20 | 21 | 22 | 23 | 24 | stopthread 25 | 26 | false 27 | 1 28 | 29 | 3000 30 | 10 31 | 1502101593000 32 | 1502101593000 33 | true 34 | 35 | 36 | 37 | 38 | 39 | true 40 | 41 | 42 | 43 | false 44 | { 45 | "head":{}, 46 | "body":{ 47 | "userId":"${userId}", 48 | "productId":"${productId}" 49 | } 50 | } 51 | = 52 | 53 | 54 | 55 | 127.0.0.1 56 | 8080 57 | 58 | 59 | http 60 | UTF-8 61 | /SecKillDesign/seckill/baseOnAtomicInteger 62 | POST 63 | true 64 | false 65 | true 66 | false 67 | Java 68 | false 69 | 70 | 71 | 72 | 73 | false 74 | 75 | saveConfig 76 | 77 | 78 | true 79 | true 80 | true 81 | 82 | true 83 | true 84 | true 85 | true 86 | false 87 | true 88 | true 89 | false 90 | false 91 | false 92 | false 93 | false 94 | false 95 | false 96 | false 97 | 0 98 | true 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 106 | false 107 | 108 | saveConfig 109 | 110 | 111 | true 112 | true 113 | true 114 | 115 | true 116 | true 117 | true 118 | true 119 | false 120 | true 121 | true 122 | false 123 | false 124 | false 125 | false 126 | false 127 | false 128 | false 129 | false 130 | 0 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | , 141 | 142 | /usr/twc/gitProject/SecKillDesign/src/main/resources/jmeter/param.txt 143 | false 144 | true 145 | shareMode.all 146 | false 147 | userId,productId 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /src/main/resources/sql/seckill.sql: -------------------------------------------------------------------------------- 1 | use seckill; 2 | 3 | DROP TABLE IF EXISTS user; 4 | CREATE TABLE user( 5 | id INT NOT NULL AUTO_INCREMENT PRIMARY KEY comment "ID", 6 | username VARCHAR (20) UNIQUE NOT NULL comment "用户名", 7 | phone VARCHAR (20) NOT NULL comment "手机号码", 8 | createTime DATE NOT NULL comment "创建时间" 9 | ); 10 | 11 | DROP TABLE IF EXISTS product; 12 | CREATE TABLE product( 13 | id INT NOT NULL AUTO_INCREMENT PRIMARY KEY comment "ID", 14 | productName VARCHAR (20) UNIQUE NOT NULL comment "产品名称", 15 | price DECIMAL(16,3) NOT NULL comment "价格", 16 | stock INT NOT NULL comment "库存", 17 | createTime DATE NOT NULL comment "创建时间" 18 | ); 19 | 20 | DROP TABLE IF EXISTS record; 21 | CREATE TABLE record( 22 | id INT NOT NULL AUTO_INCREMENT PRIMARY KEY comment "ID", 23 | userId INT NOT NULL comment "用户ID", 24 | productId INT NOT NULL comment "产品ID", 25 | state VARCHAR (6) NOT NULL comment "秒杀状态1秒杀成功,0秒杀失败,-1重复秒杀,-2系统异常", 26 | stateInfo VARCHAR (6) NOT NULL comment "状态的明文标识", 27 | createTime DATE NOT NULL comment "创建时间" 28 | ); 29 | 30 | -- use seckill; 31 | -- update product set stock=100 where id>=1; 32 | -- delete from record where id>=0 33 | 34 | -- update product set stock=100 and version=0 where id>=1 ; -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/atomicInteger/result_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/atomicInteger/result_1.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/atomicInteger/result_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/atomicInteger/result_2.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/atomicInteger/result_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/atomicInteger/result_3.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/pessLockInMySQL/result_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/pessLockInMySQL/result_1.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/pessLockInMySQL/result_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/pessLockInMySQL/result_2.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/pessLockInMySQL/result_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/pessLockInMySQL/result_3.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/posiLockInMySQL/result_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/posiLockInMySQL/result_1.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/posiLockInMySQL/result_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/posiLockInMySQL/result_2.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/posiLockInMySQL/result_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/posiLockInMySQL/result_3.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/posiLockInRedis/result_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/posiLockInRedis/result_1.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/posiLockInRedis/result_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/posiLockInRedis/result_2.png -------------------------------------------------------------------------------- /src/main/resources/stress_test_result/posiLockInRedis/result_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SkyScraperTwc/SecKillDesign/f1736364e464d79aeb9d9f27c1b0e447c9d869ae/src/main/resources/stress_test_result/posiLockInRedis/result_3.png -------------------------------------------------------------------------------- /src/test/java/JUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.scut.seckill; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.scut.seckill.cache.RedisCacheHandle; 5 | import com.scut.seckill.common.SecKillEnum; 6 | import com.scut.seckill.constant.RedisCacheConst; 7 | import com.scut.seckill.entity.Record; 8 | import com.scut.seckill.entity.User; 9 | import com.scut.seckill.mapper.SecKillMapper; 10 | import com.scut.seckill.utils.SecKillUtils; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.test.context.junit4.SpringRunner; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | import org.springframework.web.bind.annotation.RequestParam; 18 | import redis.clients.jedis.Jedis; 19 | import redis.clients.jedis.Response; 20 | import redis.clients.jedis.Transaction; 21 | import sun.rmi.runtime.Log; 22 | 23 | import java.io.BufferedWriter; 24 | import java.io.File; 25 | import java.io.FileWriter; 26 | import java.io.IOException; 27 | import java.util.*; 28 | import java.util.concurrent.atomic.AtomicInteger; 29 | 30 | @RunWith(SpringRunner.class) 31 | @SpringBootTest 32 | public class JUnitTest { 33 | 34 | @Autowired 35 | private SecKillMapper secKillMapper; 36 | 37 | @Autowired 38 | private RedisCacheHandle redisCacheHandle; 39 | 40 | private Set set = new TreeSet<>(); 41 | 42 | @Test 43 | public void test2() throws InterruptedException { 44 | Jedis jedis = redisCacheHandle.getJedis(); 45 | boolean isBuy = jedis.sismember(RedisCacheConst.IPHONE_HAS_BOUGHT_SET, "1"); 46 | System.out.println(isBuy); 47 | } 48 | 49 | @Test 50 | public void test3() throws InterruptedException, IOException { 51 | String[] array = {"1","2","3","4","5","6"}; 52 | File file =new File("/usr/twc/gitProject/SecKillDesign/src/main/resources/jmeter/789.txt"); 53 | FileWriter fileWritter = new FileWriter(file); 54 | BufferedWriter bufferWritter = new BufferedWriter(fileWritter); 55 | Random random = new Random(); 56 | for (int i = 8483; i <= 10000; i++) { 57 | StringBuffer buffer = new StringBuffer(""); 58 | buffer.append(i+","); 59 | int max=6; 60 | int min=0; 61 | int s = random.nextInt(max)%(max-min+1) + min; 62 | buffer.append(array[s]); 63 | System.out.println(buffer.toString()); 64 | // bufferWritter.write(buffer.toString()); 65 | // bufferWritter.newLine();//换行 66 | } 67 | } 68 | 69 | @Test 70 | public void createUserSQL() throws IOException { 71 | List list = new ArrayList<>(); 72 | File file =new File("/usr/twc/gitProject/SecKillDesign/src/main/resources/sql/insert.sql"); 73 | FileWriter fileWritter = new FileWriter(file); 74 | BufferedWriter bufferWritter = new BufferedWriter(fileWritter); 75 | for (int i=1001;i<=10000;i++){ 76 | StringBuffer buffer = new StringBuffer("INSERT INTO `user` VALUES ('0', "); 77 | buffer.append("'"+"tom_"+i+"'"+","); 78 | buffer.append("'13855558888'"+","); 79 | buffer.append("current_date());"); 80 | list.add(buffer.toString()); 81 | } 82 | for (String string :list) { 83 | //INSERT INTO `user` VALUES ('0', 'tom_850','13855558888',current_date()); 84 | System.out.println(string); 85 | bufferWritter.write(string); 86 | bufferWritter.newLine();//换行 87 | } 88 | bufferWritter.close(); 89 | } 90 | 91 | @Test 92 | public void test4() throws InterruptedException { 93 | Jedis jedis = redisCacheHandle.getJedis(); 94 | Transaction tx = jedis.multi(); 95 | 96 | Response isBuy = tx.sismember("set", "2"); 97 | System.out.println("isBuy------"+isBuy); 98 | 99 | Response decrResult = tx.hincrBy("product_1","stock",-1); 100 | System.out.println("decrResult------"+decrResult); 101 | 102 | tx.sadd("set","1"); 103 | 104 | List resultList = tx.exec(); 105 | System.out.println("-----------"); 106 | System.out.println(Boolean.valueOf(resultList.get(0).toString())); 107 | System.out.println( Integer.parseInt(resultList.get(1).toString())); 108 | System.out.println( Integer.parseInt(resultList.get(2).toString())); 109 | } 110 | 111 | 112 | @Test 113 | public void redisSetTest() throws InterruptedException { 114 | Jedis jedis = redisCacheHandle.getJedis(); 115 | 116 | long l = jedis.sadd("myset", "123"); 117 | System.out.println(l); 118 | long l2 = jedis.sadd("myset", "123"); 119 | System.out.println(l2); 120 | 121 | boolean flag = jedis.sismember("myset","123"); 122 | System.out.println(flag); 123 | } 124 | 125 | @Test 126 | public void userTest() throws InterruptedException { 127 | User user = secKillMapper.getUserById(1); 128 | System.out.println(user); 129 | 130 | AtomicInteger atomicInteger = new AtomicInteger(); 131 | } 132 | } 133 | --------------------------------------------------------------------------------