With the development of the Internet and the increasing demand of consumers, the sales of goods have become increasingly fierce. For merchants, the most intuitive solution is promotions. However, promotions can also cause certain risks.
If handled improperly, problems such as insufficient inventory during the "rush-up" activity may occur. This article will use Redis to achieve product flash sale to avoid these problems.
Technology stack
The technology stack used in this implementation is as follows:
- SpringBoot
- Redis
- Mybatis-plus
- Vue
Function implementation steps
Before realizing product flash sale, we need to prepare a basic development environment first. This article will assume that you have set up the relevant environment.
Next, please follow the steps below to implement the function.
Step 1: Prepare product inventory data
First, we need to create a table named "goods" in the database to store inventory data of the goods.
The table structure is as follows:
CREATE TABLE `goods` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Flash sale product ID', `goods_name` varchar(32) DEFAULT NULL COMMENT 'Product Name', `goods_count` int(11) DEFAULT NULL COMMENT 'Commodity Inventory Quantity', `start_time` datetime DEFAULT NULL COMMENT 'Flash start time', `end_time` datetime DEFAULT NULL COMMENT 'Flash kill end time', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Add some fake data to the table to test the flash sale function.
Step 2: Realize product killing instantly
Next, we need to implement the product flash sale function. Here, we use Redis as the core tool for flash sales and realize flash sales through front-end collaboration.
1. Redis realizes instant kill
In Redis, we can use the List type to store the product ID to be sold instantly, and use the Set type to store the product ID that has been sold instantly. At the same time, in order to prevent a user from repeatedly buying the same product, we also need to use the Hash type to store each user's flash sale order information.
The specific implementation method is as follows:
- Initialize the product list and flash-selled product collection in Redis, and store the inventory quantity of the product in the database into Redis.
// Product List NameString redisKey = "goods:" + (); // Add all stock itemsfor (int i = 0; i < (); i++) { ().rightPush(redisKey, (())); }
- Determine whether the user has successfully sold it.
// Check whether the user has already sold the product in secondsObject orderObj = ().get("seckill_orders", () + ":" + ()); if (orderObj != null) { throw new SEckillException(ErrorCodeEnum.REPEAT_SEC_KILL_ERROR); } // Check whether the user is queueingObject userInQueueObj = ().isMember("seckill_queues:" + (), ()); if (userInQueueObj != null) { throw new SEckillException(ErrorCodeEnum.WAITING_IN_QUEUE_ERROR); }
- Use Redis's transactions to implement the logic of handling successful snap-ups.
// Start transactions(true); (); // A product pops up from the product list().leftPop(redisKey); // Use setValueAt and other methods to obtain user information and product information. Skip this here// Determine whether product information has been obtainedif (seckillGoods == null) { (); throw new SEckillException(ErrorCodeEnum.SEC_KILL_FINISH_ERROR); } // Flash sale is successful, generate a flash sale order().put("seckill_orders", () + ":" + (), seckillOrder); // Write the product that has successfully sold instantly into the Set().add("seckill_success:" + (), (())); // Submit transaction();
The above code, when the flash sale is successfully achieved by transacting Redis, the product list pops up from an element, saves the flash sale order into the Hash, and adds records in the flash sale product collection. When the flash sale fails, Redis will automatically roll back the entire transaction.
2. Implement instant killing on the front-end page
In the front-end page, we need to use Vue to send two requests at the same time, one request is used to obtain product details, and the other request is used to submit flash sale orders. The specific implementation method is as follows:
- Get product details.
created() { // Send a request to obtain product details ('/seckill/goods/' + this.$) .then(res => { = ; }) .catch(err => { (err); }) }
- Submit a flash sale order.
seckill() { // Send a flash sale request ('/seckill/order/' + ) .then(res => { if ( == 200) { alert('Successfully killed instantly! '); } else { alert(); } }) .catch(err => { (err); }) }
The above code implements the flash sale function by using Axios to send product details and flash sale requests to the backend.
Step 3: Optimize Redis performance
In actual projects, we need to consider how to optimize Redis performance. Here are some optimized configuration solutions:
- Increase the number of Redis instances to improve availability and performance.
- Set the expiration time of Redis cache to prevent memory leakage and waste of Redis storage space.
- Use Redis's clustering function to distribute data across multiple Redis nodes to improve Redis' fault tolerance.
Technical explanation
Next, let us explain the implementation techniques and principles of this project in more detail.
Redis List type
When implementing product flash sale, we need to use Redis' List type to store the product ID to be flash sale, and use operations such as departing from the left and joining the right to simulate the purchase process.
Redis's List type is a bidirectional linked list structure that can insert and delete data at the head, tail, and anywhere. Using the List type can implement functions similar to queues and stacks.
Here are some commands using Redis's List type:
-
LPUSH
: Insert one or more elements to the left of the list. -
RPUSH
: Insert one or more elements to the right of the list. -
LPOP
: Removes an element from the left side of the list and returns. -
RPOP
: Removes an element from the right side of the list and returns. -
LINDEX
: Returns the element in the list with the specified index position.
Redis Set Type
When implementing product flash sale, we also need to use Redis Set type to store product IDs that have been successfully sold.
Redis's Set type is an unordered collection that can store multiple elements of string type. Set types support deduplication and collection operations.
Here are some commands that use Redis's Set type:
-
SADD
: Add one or more elements to the collection. -
SREM
: Removes the given element from the collection. -
SCARD
: Returns the number of elements in the collection. -
SMEMBERS
: Returns all elements in the collection. -
SISMEMBER
: Determine whether the element is in the set.
Redis Hash Type
When implementing product flash sale, we also need to use Redis’ Hash type to store each user’s flash sale order information.
The Hash type of Redis is a dictionary structure that can store, modify and query elements in O(1) time.
Here are some commands using Redis's Hash type:
-
HSET
: Sets the value of the specified field in the hash table. -
HGET
: Gets the value of the specified field in the hash table. -
HGETALL
: Get all fields and values in the hash table. -
HDEL
: Delete one or more fields in the hash table. -
HEXISTS
: Determine whether the specified field in the hash table exists.
Redis's transactions
When implementing product flash sale, we need to ensure that when the flash sale is successful, an element needs to pop up in the product list, and store the flash sale order information into the hash, and add records in the flash sale product collection. In order to ensure that these three operations are completed simultaneously, we need to use Redis transactions to ensure atomicity.
A Redis transaction is a collection of commands that are executed in one go, sequentially. During the execution of the transaction, the operations of other clients do not interfere with the execution of the transaction.
Here are some commands that use Redis transactions:
-
MULTI
: Start the transaction. -
EXEC
: Submit transaction and execute all commands in the transaction. -
DISCARD
: Revoke transactions.
Mybatis-plus
In this project, we use Mybatis-plus as the ORM framework to operate the database. Mybatis-plus is an enhanced version of Mybatis, which can greatly improve development efficiency.
Some of the characteristics of Mybatis-plus are as follows:
- Without writing a Mapper interface, you can use the automatically generated general Mapper interface to operate on the database.
- Supports Lambda expressions to improve code readability.
- Rich query condition API, supporting chain calls.
Some of the Mybatis-plus notes used in this project are as follows:
-
@TableName
: Specify the database table name corresponding to the entity class. -
@TableField
: Specify the database column name corresponding to the entity class field. -
@Autowired
: The beans that need to be used in automatic assembly in Spring.
Development Process
The development process is as follows:
- Prepare the project environment, including SpringBoot, Redis, Mybatis-plus, Vue and other components.
- Create flash sale product table searchill_goods in the database and add some test data.
- According to actual needs, the product flash sale function is implemented in the back-end code, which requires the use of Redis List, Set and Hash types, and the use of Redis transactions to ensure atomicity.
- Use Vue in the front-end page to send product details and flash sale requests to the back-end to achieve flash sale.
- Optimize Redis performance, increase the number of Redis instances, set cache expiration time, and use Redis clusters.
- Test and deploy projects.
Summarize
This article introduces how to use Redis to achieve product flash sale, and provides detailed functional implementation steps and technical explanations.
During the implementation process, we understand the List, Set and Hash types of Redis, and how to ensure atomicity using Redis transactions. At the same time, we also used Mybatis-plus as the ORM framework, effectively improving development efficiency. Finally, we also introduce how to optimize Redis performance to further improve the quality of the project.
These are just personal experience. I hope you can give you a reference and I hope you can support me more.