MySQL悲观锁并发控制实现案例

该文通过一个MySQL数据库表`t_point`展示了悲观锁的实现,使用MyBatis框架进行操作。在业务层中,定义了两个方法`updateWithTimePessimistic`和`updatePessimistic`来演示悲观锁如何防止并发冲突。在Web接口中,通过两个不同的URL调用来测试悲观锁的等待机制,强调了悲观锁可能带来的性能影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MySQL悲观锁并发控制实现案例

表设计

CREATE TABLE `t_point` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `point_name` varchar(255) NOT NULL,
  `point_type` varchar(255) NOT NULL,
  `version` int(11) NOT NULL DEFAULT '1',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4

mybatis各层设计

实体层

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Point implements Serializable {
    private static final long serialVersionUID = -6823782099362425089L;

    private Integer id;

    private String pointName;

    private String pointType;

    private Integer version;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

Mapper层

PointMapper.java代码

@Mapper
public interface PointMapper {


    @Select(value = "select * from t_point where id =#{id}")
    @Results(value = {
            @Result(column = "create_time",property = "createTime",javaType = LocalDateTime.class,jdbcType = JdbcType.TIMESTAMP),
            @Result(column = "update_time",property = "updateTime",javaType = LocalDateTime.class,jdbcType = JdbcType.TIMESTAMP),

    })
    Point findById(@Param("id") Integer id);


        /**
     * 悲观锁
     * select语句后加 for update
     * 
     *  //select ... for update可以在读取数据的同时将行锁住,阻止其他事务对这些行进行修改。
     */
    @Select(value = "select * from t_point where point_name =#{name} for update")
    Point selectByPointNameForUpdate(@Param("name") String name);





    @Update(value = "update t_point set point_name=#{pointName},point_type =#{pointType},version=version+1 where id =#{id}")
    int update(Point point);


    @Select(value = "select * from t_point where point_name =#{name}")
    Point findByPointName(@Param("name") String name);


    @Insert(value = "insert into t_point (point_name ,point_type) values (#{pointName},#{pointType})")
    int save(Point point);


}

web接口及业务层

业务层

@Slf4j
@Service
public class PointService {
    @Resource
    private PointMapper pointMapper;
    
    @Transactional
    public void updateWithTimePessimistic(Point point, int time) throws InterruptedException {
        Point point1 = pointMapper.selectByPointNameForUpdate(point.getPointName());
        if (point1 == null) {
            return;
        }
        if (StrUtil.isNotBlank(point.getPointName())) {
            point1.setPointName(point.getPointName());
        }
        if (StrUtil.isNotBlank(point.getPointType())) {
            point1.setPointType(point.getPointType());
        }

        Thread.sleep(time * 1000L);
        pointMapper.update(point1);


    }

    @Transactional
    public void updatePessimistic(Point point)  {
        Point point1 = pointMapper.selectByPointNameForUpdate(point.getPointName());
        if (point1 == null) {
            return;
        }
        if (StrUtil.isNotBlank(point.getPointName())) {
            point1.setPointName(point.getPointName());
        }
        if (StrUtil.isNotBlank(point.getPointType())) {
            point1.setPointType(point.getPointType());
        }

        pointMapper.update(point1);

    }
    
}

web接口层

@RestController
public class OptimisticTestController {

    @Autowired
    private PointService pointService;
    
    //悲观锁 在数据库的访问中使用,表现为:前一次请求没执行完,后面一个请求就一直在等待
    
    //悲观锁在并发环境下可能导致性能下降,因为它会阻止其他事务对资源的访问。
   
    //
    //先访问
    //http://localhost:8615/update/20
    //接着立马访问
    //http://localhost:8615/update
    //
    //会发现,第二个请求会等待第一个请求执行完毕才会执行


    @RequestMapping("/update/{time}")
    public String update1(@RequestBody Point point, @PathVariable("time") int time) throws InterruptedException {
        pointService.updateWithTimePessimistic(point, time);
        return "0000";
    }

    @RequestMapping("/update")
    public String update2(@RequestBody Point point){
        pointService.updatePessimistic(point);
        return "0000";
    }
   
    

}
03-19
### IEEE 802.1Q VLAN Tagging Protocol Standard IEEE 802.1Q 是支持虚拟局域网(VLAN)的标准协议之一,通常被称为 Dot1q。该标准定义了一种用于以太网帧的 VLAN 标记系统以及交换机和桥接器处理这些标记帧的操作流程[^2]。 #### 协议结构概述 IEEE 802.1Q 的核心功能在于通过在以太网数据帧中插入特定字段来实现 VLAN 标签的功能。这种标签使得网络设备能够识别哪些流量属于哪个 VLAN,并据此执行转发决策。具体来说: - **Tag Header**: 在原始以太网帧头部增加了一个额外的 4 字节字段作为 VLAN 标签头。这四个字节包含了以下部分: - **Priority Code Point (PCP)**: 使用 3 比特表示优先级级别,范围从 0 到 7,主要用于 QoS 控制。 - **Canonical Format Indicator (CFI)**: 这是一个单比特位,在传统以太网环境中设置为零。 - **VLAN Identifier (VID)**: 使用 12 比特标识具体的 VLAN ID,理论上可以支持多达 4096 个不同的 VLAN(编号从 0 至 4095),其中某些特殊值保留给内部用途或管理目的。 #### 数据包处理机制 当一个带有 VLAN tag 的数据包进入支持 IEEE 802.1Q 的交换机时,它会依据此标签决定如何路由或者过滤该数据流。如果目标端口不属于同一 VLAN,则不会传输至其他无关联的物理接口上;反之亦然——只有相同 VLAN 成员之间才允许互相通信除非经过路由器跨网段访问[^1]。 此外,为了简化管理和配置过程并增强互操作性,还引入了一些辅助性的子协议和服务组件比如 GARP(通用属性注册协议)。GARP 可帮助分发有关 VLAN 成员资格的信息到各个连接节点以便动态调整其行为模式而无需频繁手动干预[^3]。 以下是创建带 VLAN TAG 的 Python 示例代码片段展示如何模拟构建这样的 Ethernet Frame: ```python from scapy.all import Ether, Dot1Q, IP, sendp def create_vlan_packet(src_mac="00:aa:bb:cc:dd:ee", dst_mac="ff:ff:ff:ff:ff:ff", vlan_id=100, src_ip="192.168.1.1", dst_ip="192.168.1.2"): ether = Ether(src=src_mac, dst=dst_mac) dot1q = Dot1Q(vlan=vlan_id) ip_layer = IP(src=src_ip, dst=dst_ip) packet = ether / dot1q / ip_layer return packet packet = create_vlan_packet() sendp(packet, iface="eth0") # Replace 'eth0' with your network interface name. ``` 上述脚本利用 Scapy 库生成包含指定源地址、目的地址及所属 VLAN 编号的数据报文并通过选定的网卡发送出去测试实际效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThinkPet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值