详解java中的悲观锁与乐观锁的区别

Java中的悲观锁和乐观锁的区别在于,悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。而乐观锁则是在操作时很乐观,认为操作不会产生并发问题 (不会有其他线程对数据进行修改),因此不会上锁。但是在更新时会判断其他线程在此之前是否已经更新过,如果没有则更新成功并返回新值;否则抛出异常或者回滚 。

悲观锁与乐观锁是并发控制中的两种主要策略,在Java中,这两种锁策略都有各自的实现方式和应用场景,本文将详细介绍悲观锁和乐观锁的概念、原理、实现以及它们在Java中的应用场景。

悲观锁

1、概念

详解java中的悲观锁与乐观锁的区别

悲观锁是一种基于数据完整性约束的并发控制策略,它假设多个事务同时访问同一数据时会发生冲突,因此在事务开始执行之前就对可能受到冲突的数据加锁,以防止其他事务对其进行修改,悲观锁的实现方式主要是通过数据库的排他锁(X锁)来实现的。

2、原理

悲观锁的原理是通过在数据表中添加一个唯一标识符(如主键),当一个事务要访问某个数据时,首先会查询该数据是否被其他事务锁定,如果被锁定,则当前事务需要等待;如果没有被锁定,则当前事务可以对该数据加上排他锁,防止其他事务对其进行修改,这样,在事务提交之前,其他事务无法对受悲观锁保护的数据进行修改,从而保证了数据的完整性和一致性。

3、实现

在Java中,悲观锁可以通过以下几种方式实现:

(1)使用数据库的排他锁(X锁):在SQL语句中使用SELECT ... FOR UPDATELOCK IN SHARE MODE来加锁。

详解java中的悲观锁与乐观锁的区别

SELECT * FROM users WHERE id = 1 FOR UPDATE;

或者

SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE;

(2)使用Java的JDBC API:通过调用Connection对象的setAutoCommit(false)方法关闭自动提交,然后调用PreparedStatement对象的executeQuery()方法执行查询并加上排他锁,调用Connection对象的commit()方法提交事务。

Connection conn = null;
PreparedStatement pstmt = null;
try {
    conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password");
    conn.setAutoCommit(false);
    pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ? FOR UPDATE");
    pstmt.setInt(1, 1);
    ResultSet rs = pstmt.executeQuery();
    // 对查询结果进行处理
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    if (conn != null) {
        try {
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            conn.close();
        }
    }
}

乐观锁

1、概念

乐观锁是一种基于版本号的并发控制策略,它假设多个事务在同一时间访问同一数据时不会发生冲突,因此不需要在事务开始执行之前就对可能受到冲突的数据加锁,乐观锁的实现方式主要是通过对数据表中每个记录的版本号字段进行更新来实现的,当一个事务要更新某个数据时,会检查该数据的版本号是否与自己读取到的版本号一致,如果一致,则更新数据并将版本号加一;如果不一致,则说明其他事务已经修改了该数据,此时可以选择重新获取数据或抛出异常,这样,在事务提交之前,其他事务只能看到已提交的数据版本,从而避免了数据的不一致性。

2、原理

乐观锁的原理是通过为每个数据记录添加一个版本号字段,并在每次更新数据时递增版本号,当一个事务要更新某个数据时,会先查询该数据的当前版本号,然后将自己的版本号设置为该值,接下来,事务会再次查询该数据的新版本号,如果新版本号与自己的版本号一致,则更新数据并将版本号加一;如果新版本号大于自己的版本号,则说明其他事务已经修改了该数据,此时可以选择重新获取数据或抛出异常,这样,在事务提交之前,其他事务只能看到已提交的数据版本,从而避免了数据的不一致性。

详解java中的悲观锁与乐观锁的区别

3、实现

在Java中,乐观锁可以通过以下几种方式实现:

(1)使用数据库的支持:许多关系型数据库都支持乐观锁机制,例如InnoDB和MyISAM等,这些数据库通常会在插入或更新数据时自动生成一个唯一的行ID(如MySQL的AUTO_INCREMENT),并将其作为版本号。

INSERT INTO users (name, age) VALUES ('张三', 25) ON DUPLICATE KEY UPDATE name='李四', age=26; -如果插入成功,则不返回任何值;如果插入失败(因为id重复),则返回1;如果更新成功(且没有其他事务修改该数据),则返回0;如果更新失败(或有其他事务修改该数据),则返回2;如果更新失败(但有其他事务插入了相同的id),则返回3。

(2)使用Java的JDBC API:通过调用PreparedStatement对象的executeUpdate()方法执行更新操作。

Connection conn = null;
PreparedStatement pstmt = null;
try {
    conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password");
    int affectedRows = pstmt = conn.prepareStatement("INSERT INTO users (name, age) VALUES (?, ?) ON DUPLICATE KEY UPDATE name=?, age=?") // 如果插入成功,则不返回任何值;如果插入失败(因为id重复),则返回1;如果更新成功(且没有其他事务修改该数据),则返回0;如果更新失败(或有其他事务修改该数据),则返回2;如果更新失败(但有其他事务插入了相同的id),则返回3,pstmt.setString(1, "张三"); pstmt.setInt(2, 25); pstmt.setString(3, "李四"); pstmt.setInt(4, 26); affectedRows = pstmt.executeUpdate(); // affectedRows为受影响的行数或相应的错误代码。
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (affectedRows == SQLErrorCode.ER_DUP_ENTRY_ON_INDEX) { // 如果受影响的行数为2或3,则表示发生了行级锁定或死锁,可以在应用程序中根据具体情况选择重试或终止操作。
            } else if (affectedRows == SQLErrorCode.ER_ROW_IS_REFERENCED_BY_OTHER_TABLE) { // 如果受影响的行数为4或5,则表示发生了外键约束冲突,可以在应用程序中根据具体情况选择重试或终止操作。
            } else if (affectedRows == SQLErrorCode.ER_NO_SUCH_TABLE || affectedRows == SQLErrorCode.ER_BAD_NULL_ERROR || affectedRows == SQLErrorCode.ER_ACCESS_DENIED || affectedRows == SQLErrorCode.ER_HOST_IS_BLOCKED) { // 如果受影响的行数为0、1、7或8,则表示发生了连接错误或其他未知错误,可以在应用程序中根据具体情况选择重试或终止操作。
            } else if (affectedRows == SQLErrorCode.ACQUIRED) { // 如果受影响的行数为9或10,则表示发生了死锁,可以在应用程序中根据具体情况选择重试或终止操作,else if (affectedRows == SQLErrorCode.COMMITTED) { // 如果受影响的行数为11或12,则表示更新成功且没有其他事务修改该数据,可以在应用程序中根据具体情况选择继续操作或提交事务,else if (affectedRows == SQLErrorCode.ROLLBACKED || affectedRows == SQLErrorCode.UNKNOWN) { // 如果受影响的行数为13或14,则表示更新失败或发生了未知错误,可以在应用程序中根据具体情况选择重试或回滚事务,else if (affectedRows == SQLErrorCode.SERIALIZATION_FAILED || affectedRows == SQLErrorCode.GENERIC_FAILURE || affectedRows == SQLErrorCode.DATA_READONLY || affectedRows == SQLErrorCode.DATA_WRONG_TYPE || affectedRows == SQLErrorCode.FEATURE_NOT_SUPPORTED || affectedRows == SQLErrorCode.CONNECTION_DOES_NOT_EXIST || affectedRows == SQLErrorCode.CONNECTION_FAILURE || affectedRows == SQLErrorCode.CONNECTION_BROKEN || affectedRows == SQLErrorCode.TRANSACTION_CONFLICT || affectedRows == SQLErrorCode.TRANSACTION_UNCOMPLETED || affectedRows == SQLErrorCode.TRANS

原创文章,作者:K-seo,如若转载,请注明出处:https://www.kdun.cn/ask/261386.html

Like (0)
Donate 微信扫一扫 微信扫一扫
K-seo的头像K-seoSEO优化员
Previous 2024-01-25 11:16
Next 2024-01-25 11:18

相关推荐

  • Oracle读写一致性的概念是什么

    Oracle读写一致性是指在并发访问数据库时,保证读取到的数据与写入数据时的原始状态一致。

    2024-05-18
    0101
  • oracle产生死锁的原因有哪些

    Oracle死锁的产生主要源于多个线程或进程对同一资源的争抢或相互依赖,比如在删除和更新之间就可能引发死锁。频繁操作数据库的update、insert、delete语句也有可能导致死锁。在事务处理中,如果没有正确提交事务或回滚事务,可能会产生死锁。还有一种情况就是管理员设置的密码到期,时间到了也会触发锁定。

    2024-01-21
    0213
  • mysql中怎么使用MVCC来解决幻读

    在MySQL中,通过使用MVCC(多版本并发控制)技术,可以解决幻读问题。

    2024-05-15
    081
  • Oracle事务隐形提交的神秘面纱

    Oracle事务隐形提交的神秘面纱在Oracle数据库中,事务是一组原子性的操作序列,这些操作要么全部成功,要么全部失败,事务的提交是一个重要的环节,它标志着一个事务的开始和结束,在Oracle数据库中,有一种名为“隐形提交”的现象,让许多开发者感到困惑,本文将揭开Oracle事务隐形提交的神秘面纱,帮助大家更好地理解和掌握这一技术。……

    2024-03-27
    0103
  • RocketMq的事务消息是什么

    RocketMQ的事务消息是什么?RocketMQ是一款分布式消息中间件,广泛应用于异步通信、解耦、削峰填谷等场景,在RocketMQ中,事务消息是一种具有原子性、一致性、隔离性和持久性的的消息保证业务流程正确执行的方式,事务消息可以确保在消息发送、处理和存储过程中,如果任何一个环节出现问题,都能保证业务流程不会出现错误,从而实现高可……

    2023-12-19
    0129
  • Oracle中断查询语句的原理

    深入理解Oracle中断查询语句的原理Oracle数据库是企业级应用中广泛使用的一种关系型数据库,其功能强大,性能稳定,在日常开发和维护过程中,我们经常会遇到需要对数据库进行查询的情况,为了提高查询效率,Oracle提供了一种中断查询的机制,即通过设置一个中断点,当满足一定条件时,中断当前的查询操作,执行其他任务,本文将对Oracle……

    2024-03-24
    0179

发表回复

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

免备案 高防CDN 无视CC/DDOS攻击 限时秒杀,10元即可体验  (专业解决各类攻击)>>点击进入