简单基于Oracle实现分布式锁

首先还原一个线程不安全的事故现场:

运行结果:

明显是有问题的,相同的票售出了多次。

基于Oracle实现简单的分布式锁

创建一个仅有一个主键字段的表:

数据库实体类:

@Table(name = "oracle_lock")
@Setter
@Getter
@AllArgsConstructor
public class OracleLockEntity {

    @Id
    @Column(name = "id")
    private String id;
}

Mapper接口:

/**
 * @author Dongguabai
 * @date 2018-07-20 11:01
 */
public interface OracleLockMapper extends Mapper<OracleLockEntity> {
}

Lock接口的方法太多,现在建一个中间实现类:

/**
 * @author Dongguabai
 * @date 2018-07-20 11:13
 */
public class LockDecorator implements Lock{
    @Override
    public void lock() {

    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public void unlock() {

    }

    @Override
    public Condition newCondition() {
        return null;
    }
}

编写数据库锁:

/**
 * Oracle分布式锁
 * 注意:1.性能较差
 * 2.可能会出现死锁(比如解锁的时候数据库挂了)
 * 3.代码复杂
 * 4.不可重入
 *
 * @author Dongguabai
 * @date 2018-07-20 10:56
 */
@Component("simpleOracleLock")
@Slf4j
public class SimpleOracleLock extends LockDecorator {

    public static final String LOCK_ID = "1";
    public static final OracleLockEntity LOCK_ORACLE_ENTITY = new OracleLockEntity(LOCK_ID);

    @Autowired
    private OracleLockMapper oracleLockMapper;

    /**
     * 非阻塞式加锁
     *
     * @return
     */
    @Override
    public boolean tryLock() {
        try {
            oracleLockMapper.insert(LOCK_ORACLE_ENTITY);
        } catch (Exception e) {
            log.info("尝试加锁失败!");
            return false;
        }
        return true;
    }

    /**
     * 解锁
     */
    @Override
    public void unlock() {
        oracleLockMapper.deleteByPrimaryKey(LOCK_ID);
    }

    /**
     * 阻塞式加锁
     */
    @Override
    public void lock() {
        if (!tryLock()) {
            int randomSleepMillis = new Random().nextInt(100);
            try {
                Thread.sleep(randomSleepMillis);
            } catch (InterruptedException e) {
                log.info("尝试加锁失败,线程sleep{}毫秒!", randomSleepMillis);
            }
            lock();
        }
    }

}

运行测试:

    @Resource(name = "simpleOracleLock")
    private Lock simpleOracleLock;

    @Test
    public void test22() throws InterruptedException {
        RunnableImpl runnable = new RunnableImpl();
        Thread t1 = new Thread(runnable, "售票窗口一");
        Thread t2 = new Thread(runnable, "售票窗口二");
        Thread t3 = new Thread(runnable, "售票窗口三");
        Thread t4 = new Thread(runnable, "售票窗口四");

        t1.start();
        t2.start();
        t3.start();
        t4.start();

        //主线程等待子线程执行完毕
        Thread.currentThread().join();
    }

    class RunnableImpl implements Runnable {

        @Override
        public void run() {
            while (sum > 0) {
                simpleOracleLock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "现在卖了第" + (sum--) + "张票");
                }catch (Exception e){

                }finally {
                    simpleOracleLock.unlock();
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

运行结果:

符合要求,按照顺序票一个个卖出去了。

Oracle实现分布式锁时,可以使用悲观锁的方式。悲观锁可以通过使用SELECT ... FOR UPDATE语句来实现排他锁,确保同一时刻只有一个事务可以获取到锁并执行相应操作,其他事务需要等待锁释放后才能获取锁。这种方式可以通过在数据库中创建一个表来实现,表中的一行记录代表一个锁,当事务需要获取锁时,使用SELECT ... FOR UPDATE语句查询对应的行记录,并进行更新操作,其他事务在进行相同查询时会被阻塞,直到锁被释放。请注意,使用数据库实现分布式锁可能会导致性能较差,并且可能出现死锁的情况,因此需要谨慎设计和使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [简单基于Oracle实现分布式锁](https://blog.csdn.net/Dongguabai/article/details/81131162)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [数据库分布式锁解决方案](https://blog.csdn.net/qq_45473377/article/details/122986872)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [分布式锁三种实现方式及对比](https://download.csdn.net/download/weixin_38702844/13683028)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值