java代码实现悲观锁 悲观锁的实现方式java

java中悲观锁和乐观锁的区别

乐观锁和悲观锁的区别如下:

创新互联主要从事网站制作、成都网站制作、网页设计、企业做网站、公司建网站等业务。立足成都服务天等,十年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:18980820575

1、悲观锁是当线程拿到资源时,就对资源上锁,并在提交后,才释放锁资源,其他线程才能使用资源。

2、乐观锁是当线程拿到资源时,上乐观锁,在提交之前,其他的锁也可以操作这个资源,当有冲突的时候,并发机制会保留前一个提交,打回后一个提交,让后一个线程重新获取资源后,再操作,然后提交。和git上传代码一样,两个线程都不是直接获取资源本身,而是先获取资源的两个copy版本,然后在这两个copy版本上修改。

3、悲观锁和乐观锁在并发量低的时候,性能差不多,但是在并发量高的时候,乐观锁的性能远远优于悲观锁。

4、常用的synchronized是悲观锁,lock是乐观锁。

java怎么使用悲观锁

悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

请问一个悲观锁的问题,就是在程序中实现该如何做啊,谢谢

假如要按照你这种 悲观锁 的处理机制的话, 那么

Connection conn 要定义在外面, 也就是类这个级别。

例如

public class Test {

Connection conn;

public Product get(id) {

conn = getConn();

conn.startTraction();

...............select * from product where id = 10 for update;

}

public void update(long id) {

// 这个时候, 用类一个级别的 Conn , 不用新建

update product set name = 'xxx' where id = :id;

// 更新完毕后

Commit 事务。

关闭 Conn.

}

}

上面的只是 原理的 例子, 实际情况下,不推荐这么写

因为 如果有人 只 Product get(id) 不 update(long id) 的话, 事情就麻烦了。

Java如何实现对Mysql数据库的行锁

下面通过一个例子来说明

场景如下:

用户账户有余额,当发生交易时,需要实时更新余额。这里如果发生并发问题,那么会造成用户余额和实际交易的不一致,这对公司和客户来说都是很危险的。

那么如何避免:

网上查了下,有以下两种方法:

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}

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


网站标题:java代码实现悲观锁 悲观锁的实现方式java
当前网址:http://hbruida.cn/article/doocjhi.html