Table of contents
Distributed lock problem_demo problem
Solve the oversold problem based on synchronized lock
Distributed lock implementation scheme
Distributed lock solution_distributed lock implemented by database pessimistic lock
Distributed lock problem_demo problem
start order service 9090
Start order service 9091
Create two SpringBoot services
Start the Nginx service
Download Nginx windows service, official website http://nginx.org/en/download.html
Configure load balancing
Edit the nginx.conf file to add load balancing configuration.
upstream test{
server localhost:9090 ;
server localhost:9091 ;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://test;
}
}
Start the Nginx service
Under the nginx directory
Start the JMeter pressure measurement tool
Add Thread Group -> HTTP Request -> View Result Tree -> Aggregate Report
Set Http request parameters
View inventory data
view order data
Solve the oversold problem based on synchronized lock
Spring has carried out a unified abstraction and formed the PlatformTransactionManager transaction manager interface, and all operations such as transaction submission and rollback are entrusted to it.
The overall interface design of the transaction function
Three interface functions In a word, the transaction manager updates the transaction status based on the basic information of the transaction when operating the transaction.
method locking
public synchronized String createOrder(Integer produceId, Integer purchaseNum) { }
Declare the transaction manager
@Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
Manually create transactions
TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
Commit the transaction manually
/**
* 创建订单
*
* @param produceId 商品id
* @param purchaseNum 购买数量
* @return
*/
@Override
public synchronized String createOrder(Integer produceId, Integer purchaseNum) {
TransactionStatus transaction = platformTransactionManager.getTransaction(trans
actionDefinition);
// 1、根据商品id获取商品信息
Product product = productMapper.selectById(produceId);
// 2、判断商品是否存在
if (product == null) {
platformTransactionManager.rollback(transaction);
throw new RuntimeException("购买商品不存在");
}
log.info(Thread.currentThread().getName() + "库存数量" + product.getCount());
// 3、校验库存
if (purchaseNum > product.getCount()) {
platformTransactionManager.rollback(transaction);
throw new RuntimeException("库存不足");
}
// 4、更新库存操作
int count = product.getCount() - purchaseNum;
product.setCount(count);
productMapper.updateById(product);
// 5、创建订单
TOrder order = new TOrder();
order.setOrderStatus(1);//订单状态
order.setReceiverName("张三");
order.setReceiverMobile("18587781058");
order.setOrderAmount(product.getPrice().multiply(new BigDecimal(purchaseNum)));//订单价格
baseMapper.insert(order);
// 6、创建订单和商品关联
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(order.getId());//订单id
orderItem.setProduceId(product.getId());// 商品id
orderItem.setPurchasePrice(product.getPrice());// 购买价格
orderItem.setPurchaseNum(purchaseNum);// 购买数量
orderItemMapper.insert(orderItem);
//提交事务
platformTransactionManager.commit(transaction);
return order.getId();
}
Distributed lock solution
The distributed CAP theory tells us that "any distributed system cannot satisfy Consistency, Availability, and Partition tolerance at the same time, and can only satisfy two at the same time." Therefore, many systems are in At the beginning of the design, it is necessary to make a trade-off between these three. In most scenarios in the Internet field, it is necessary to sacrifice strong consistency in exchange for high availability of the system. The system often only needs to ensure "final consistency", as long as the final time is within the acceptable range of users.
Distributed lock implementation scheme
Distributed lock based on database implementation
The distributed lock based on the database is mainly implemented by using the unique index of the database. The unique index is naturally exclusive, which just meets our requirements for locks: only one competitor is allowed to acquire the lock at the same time.
Distributed lock based on Redis
Using Redis to implement distributed locks has the highest efficiency and the fastest locking speed, because Redis is almost a pure memory operation, while the database-based and Zookeeper-based solutions both involve disk file IO, and the efficiency is relatively low. Generally, Redis is used to implement distributed locks by using the SETNX key value command of Redis. It will only succeed when the key does not exist. If the key already exists, the command will fail.
Distributed lock based on Zookeeper
Zookeeper is generally used as a configuration center. Its principle of implementing distributed locks is similar to that of Redis. We create temporary sequential nodes in Zookeeper and use the feature that nodes cannot be created repeatedly to ensure exclusivity.
Distributed lock solution_distributed lock implemented by database pessimistic lock
What is a pessimistic lock
As the name suggests, it is a pessimistic lock, always assuming the worst case, every time you go to get the data, you think that others will modify it, so every time you get the data, you will lock it, so that others will block if they want to get the data until it gets the lock.
Demo for update
Open 2 command line interfaces
test for update
Use for update in the project
configuration file add configuration
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
mapper add method
public interface ProductMapper extends BaseMapper<Product> {
Product findById(@Param("id")Integer id);
}
Mapper writes the statement
<select id="findById" parameterType="int" resultType="com.tong.lock.entity.Product">
select * from product where id = #{id} for update
</select>
Modify the order interface implementation class
@Transactional(rollbackFor = Exception.class)
@Override
public String createOrder(Integer productId, Integer count) {
// 1、根据商品id查询商品信息
Product product = productMapper.findById(productId);
// 2、判断商品是否存在
if (product == null) {
throw new RuntimeException("购买商品不存在:" + productId + "不存在");
}
// 3、校验库存
if (count > product.getCount()) {
throw new RuntimeException("商品" +productId + "仅剩" + product.getCount() + "件,无法购买");
}
// 4、计算库存
Integer leftCount = product.getCount() - count;
// 5、更新库存
product.setCount(leftCount);
productMapper.updateById(product);
// 6、 创建订单
TOrder order = new TOrder();
order.setOrderStatus(1);//待处理
order.setReceiverName("张三");
order.setReceiverMobile("18587781068");
order.setOrderAmount(product.getPrice().multiply(new BigDecimal(count)));//订单价格
baseMapper.insert(order);
// 7、 创建订单和商品关系数据
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(order.getId());
orderItem.setProduceId(product.getId());
orderItem.setPurchasePrice(product.getPrice());
orderItem.setPurchaseNum(count);
orderItemMapper.insert(orderItem);
return order.getId();
}
Pressure measurement throughput