如何使用Spring Data JPA优雅地实现乐观锁和悲观锁

在并发数据库操作领域,处理数据完整性至关重要。 Spring Data 与 JPA(Java Persistence API)集成,提供乐观和悲观锁定机制。

乐观锁: 乐观锁的基本思想是,认为在大多数情况下,数据访问不会导致冲突。因此,乐观锁允许多个事务同时读取和修改相同的数据,而不进行显式的锁定。在提交事务之前,会检查是

否有其他事务对该数据进行了修改。如果没有冲突,则提交成功;如果发现冲突,就需要回滚并重新尝试。

乐观锁通常使用版本号或时间戳来实现。每个数据项都会包含一个表示当前版本的标识符。在读取数据时,会将版本标识符保存下来。在提交更新时,会检查数据的当前版本是否与保存的版本匹配。如果匹配,则更新成功;否则,表示数据已被其他事务修改,需要处理冲突。

乐观锁适用于读操作频率较高、写操作冲突较少的场景。它减少了锁的使用,提高了并发性能,但需要处理冲突和重试的情况。

悲观锁: 悲观锁的基本思想是,在数据访问期间假设会发生冲突,因此在访问数据之前就会对其进行锁定,阻止其他事务对该数据进行修改。

悲观锁使用排他锁(Exclusive Lock)来实现。当一个事务对数据进行修改时,它会请求排他锁,并且其他事务无法获取相同的锁直到该事务释放锁。这样可以确保在任何时候只有一个事务能够修改数据,避免了冲突。

悲观锁适用于写操作频率较高、写操作冲突较多的场景。它确保了数据的一致性和完整性,但可能降低并发性能,因为其他事务需要等待锁的释放。

选择乐观锁还是悲观锁取决于具体的应用场景和并发控制需求。乐观锁适合读多写少、冲突较少的情况,而悲观锁适合写多读少、冲突较多的情况。

Spring Data JPA 乐观锁

@Data
@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Version
    private int version;

    private String name;

    private double price;
}

public interface ProductRepository extends JpaRepository<Product, Long> {}

@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;

    public void updatePrice(Long id, double newPrice) {
        Product product = productRepository.findById(id).orElseThrow();
        product.setPrice(newPrice);
        productRepository.save(product);
    }
}

在上面的示例中,当两个线程同时尝试更新同一产品的价格时,第一个线程将成功更新该产品。但第二个线程将失败,因为版本不匹配,抛出ObjectOptimisticLockingFailureException。

updatePrice方法生成的 SQL如下:

SELECT id, name, price, version FROM product WHERE id = ?
UPDATE product SET name = ?, price = ?, version = ? WHERE id = ? AND version = ?

原理如下:

  • 在Product实体的version字段添加@Version注解。
  • 读取操作(如findById)是非阻塞的,可以由多个线程并行完成。他们不检查也不关心版本列。
  • 写入操作(如save)将检查版本列,以确保数据自读取以来未发生更改。如果另一个线程同时更新了数据(因此增加了版本号),则保存操作将失败并显示 ObjectOptimisticLockingFailureException。

如果你想确保读取操作是最新的或在读取时阻止其他操作,则需要采用悲观锁定策略,例如 PESSIMISTIC_READ 或 PESSIMISTIC_WRITE。

Spring Data JPA 悲观锁

@Data
@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private double price;
}

public interface ProductRepository extends JpaRepository<Product, Long> {
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    Optional<Product> findByIdLocked(Long id);
}

@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;

    @Transactional
    public void updatePrice(Long id, double newPrice) {
        Product product = productRepository
            .findByIdLocked(id)
            .orElseThrow(EntityNotFoundException::new);
        product.setPrice(newPrice);
    }
}

@Lock(LockModeType.PESSIMISTIC_WRITE) 注解确保在调用 findByIdLocked 时获得写锁。

此处,@Transactional 注释在调用 updatePrice 时启动新事务。如果该方法成功完成,则事务提交,如果抛出异常,则回滚。

生成的SQL:

用锁获取:

SELECT id, name, price FROM product WHERE id = ? FOR UPDATE

updatePrice SQL如下:

UPDATE product SET name = ?, price = ? WHERE id = ?

悲观锁提供了一种通过在事务的整个持续时间内获取锁定来防止并发数据访问冲突的方法。此方法在高争用场景中特别有用。然而,必须意识到死锁的可能性以及对系统吞吐量的影响。正确的事务管理(如 @Transactional 所示)可确保操作的原子性。

结论:

在 Spring Data JPA 的事务管理和数据一致性方面,我们有两种主要的锁定策略可供使用:

  • @Transactional+@Lock(LockModeType.PESSIMISTIC_WRITE):这种组合实现了悲观锁定方法。当使用此配置执行读取操作时,应用程序将锁定数据库中的特定行,以防止其他事务修改它,直到当前事务完成。虽然这确保了严格的一致性并防止冲突,但在某些情况下,由于等待释放锁的时间可能会降低吞吐量。
  • @Version:该注解采用乐观锁定策略。这里,当读取数据时,不应用锁。相反,在尝试更新时,Spring Data JPA 会检查自上次读取以来数据的版本是否已被另一个事务修改。如果发生此类修改,则会抛出 ObjectOptimisticLockingFailureException 。该策略假设冲突很少,并且大多数交易将在不受干扰的情况下进行。

根据特定的用例和性能要求,开发人员可以在悲观锁定和乐观锁定之间进行选择。每种方法都有其独特的优点和挑战。该决定取决于并发数据访问的预期频率以及管理数据一致性所需的严格程度。

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/241756.html<

(0)
运维的头像运维
上一篇2025-04-24 11:51
下一篇 2025-04-24 11:52

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注