java如何实现对mysql数据库的行锁

指尖挥舞 指尖挥舞     2022-07-31     722

关键词:

场景如下:
    用户账户有余额,当发生交易时,需要实时更新余额。这里如果发生并发问题,那么会造成用户余额和实际交易的不一致,这对公司和客户来说都是很危险的。
那么如何避免:
    网上查了下,有以下两种方法:
    1、使用悲观锁
            当需要变更余额时,通过代码在事务中对当前需要更新的记录设置for update行锁,然后开始正常的查询和更新操作
            这样,其他的事务只能等待该事务完成后方可操作
            当然要特别注意,如果使用了Spring的事务注解,需要配置一下:
    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->  
    <bean id="transactionManager"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean>
    <!-- 使用annotation定义事务 -->
     <tx:annotation-driven transaction-manager="transactionManager" />

 在指定代码处添加事务注解

@Transactional
    @Override
    public boolean increaseBalanceByLock(Long userId, BigDecimal amount)
        throws ValidateException {
        long time = System.currentTimeMillis();
        //获取对记录的锁定
        UserBalance balance = userBalanceDao.getLock(userId);
        LOGGER.info("[lock] start. time: {}", time);
        if (null == balance) {
            throw new ValidateException(
                ValidateErrorCode.ERRORCODE_BALANCE_NOTEXIST,
                "user balance is not exist");
        }
        boolean result = userBalanceDao.increaseBalanceByLock(balance, amount);
        long timeEnd = System.currentTimeMillis();
        LOGGER.info("[lock] end. time: {}", timeEnd);
        return result;
    }

MyBatis中的锁定方式,实际测试该方法确实可以有效控制,不过在大并发量的情况下,可能会有性能问题吧

  <select id="getLock" resultMap="BaseResultMap" parameterType="java.lang.Long">
        <![CDATA[
            select * from user_balance where id=#{id,jdbcType=BIGINT} for update;
        ]]>
    </select>

 

    2、使用乐观锁
            这个方法也同样可以解决场景中描述的问题(我认为比较适合并不频繁的操作):
            设计表的时候增加一个version(版本控制字段),每次需要更新余额的时候,先获取对象,update的时候根据version和id为条件去更新,如果更新回来的数量为0,说明version已经变更
            需要重复一次更新操作,如下:sql脚本
            
update user_balance set Balance = #{balance,jdbcType=DECIMAL},Version = Version+1 where Id = #{id,jdbcType=BIGINT} and Version = #{version,jdbcType=BIGINT}

 这是一种不使用数据库锁的方法,解决方式也很巧妙。当然,在大量并发的情况下,一次扣款需要重复多次的操作才能成功,还是有不足之处的。不知道还有没有更好的方法。

面试题2:mysql的行锁

mysql的锁是由具体的存储引擎实现的。InnoDB支持行锁和事务Mysql有三种级别的锁定:表级锁定、页级锁定、行级锁定  查看详情

行锁功过:怎么减少行锁对性能的影响?

...重要原因之一。我们今天就主要来聊聊InnoDB的行锁,以及如何通过减少锁冲突来提升业务并发度。顾名思义, 查看详情

mysql的行锁

...时看完了MySQL的全局锁、表级锁还有行锁和间隙锁。其中的行锁和间隙锁迟迟无法理解,最近趁着有空再次阅读了一遍,并且对照了《深入浅出MySQL》,发现对MySQL锁的理解又上了一个台阶,今天就来分享一下MySQL... 查看详情

mysql中的行锁(代码片段)

1、行锁分类1、记录锁:即锁住记录本身2、间隙锁:锁住一段没有记录的间隙,可以是两条记录的中间部分,也可以是第一条记录的前置部分或最后一条记录的后续部分2.1需要注意的是,间隙锁仅仅是阻塞对... 查看详情

mysql中innodb引擎的行锁是通过加在啥上完成

...到的此类问题,大致可以分为以下几种原因:1.程序中非数据库交互操作导致事务挂起将接口调用或者文件操作等这一类非数据库交互操作嵌入在SQL事务代码之中,那么整个事 查看详情

mysql中innodb的行锁算法

...法进行的一些实验。锁的算法为:我知道是行锁,但是是如何锁的,锁多少数据假如有个索引是:[1,2,3,7]recordlock锁的是1,2,3,7gaplock锁的是(-,1),(2,3),(3,7),(7,+)反正锁的就是区间,不是行next-keylock锁的是(-... 查看详情

mysql-锁

InnoDB行锁实现方式InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,... 查看详情

mysql行锁等待异常

...到的此类问题,大致可以分为以下几种原因:1.程序中非数据库交互操作导致事务挂起将接口调用或者文件操作等这一类非数据库交互操作嵌入在SQL事务代码之中,那么整个事务很有可能因此挂起(接口不通等待超时或是上传下... 查看详情

mysql死锁(代码片段)

...形成死锁两阶段锁协议产生死锁的四个必要条件三、MySQL如何处理死锁?杀死进程MySQL表间隙锁排他锁共享锁分析行锁定行锁优化四、如何避免发生死锁1.对索引加锁顺序的不一致很可能会导致死锁;2.Gap锁往往是程序中导... 查看详情

mysql死锁(代码片段)

...形成死锁两阶段锁协议产生死锁的四个必要条件三、MySQL如何处理死锁?杀死进程MySQL表间隙锁排他锁共享锁分析行锁定行锁优化四、如何避免发生死锁1.对索引加锁顺序的不一致很可能会导致死锁;2.Gap锁往往是程序中导... 查看详情

关于mysql中的表锁和行锁

...算机协调多个进程或纯线程并发访问某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所在有数据库必须解决的一个... 查看详情

mysql支持多用户同时读写吗

数据库是支持多用户访问的,因此需要一种机制保证多个用户同时读取和修改数据时,数据不会被破坏或者失效。在MySQL中,使用锁来保证并发连接情况下的数据准确性。InnoDB中的锁定技术往往是基于索引实现的,如果SQL中没有... 查看详情

跑了4个实验,实战讲解mysql的行锁间隙锁...(代码片段)

...总java生态圈常用技术框架、开源中间件,系统架构、数据库、大公司架构案例、常用三方类库、项目管理、线上问题排查、个人成长、思考等知识大家好,我是Tom哥~今天跟大家聊一聊MySQL的事务隔离,并通过一些实... 查看详情

mysql数据库锁(代码片段)

MySQL数据库锁锁的分类按照对数据操作的类型(读/写)进行分类对数据操作的粒度分类表锁锁表---读表查看表上加过的锁释放所有表锁注意锁表---写表总结如何分析表锁定行锁行锁演示索引失效会导致行锁变成表锁间隙锁如何锁定... 查看详情

mysql基础篇之行锁--07(代码片段)

...讲讲MySQL的行锁。MySQL的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如MyISAM引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁,对于这种引擎的表,同 查看详情

关于数据库行锁与表锁的认识(代码片段)

MySQLMySQL(InnoDB存储引擎)默认是自动提交事务的,所以这个测试,需要先将MySQL的autocommit设置为0,关闭自动提交,需要自己手动提交事务--关闭自动提交setautocommit=0;--开启事务begin;这里我主要针对的是悲观锁,其实也就是行锁和表... 查看详情

mysql锁--02---行锁(记录锁(recordlocks))(代码片段)

...务==ACID并发事务带来的问题事务隔离级别常看当前数据库的事务隔离级别:showvariableslike'tx_isolation';MySQL-行锁InnoDB实现了以下两种类型的行锁。**共享锁(S)**:**排他锁(X)**:InnoDB加锁规... 查看详情

day871.行锁-mysql实战(代码片段)

...关于行锁的内容。MySQL的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如MyISAM引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁,对于这种引擎的表,同一张表上任何时刻只... 查看详情