sp\u getapplock可以在spring应用程序中用作分布式锁定机制吗?

o8x7eapl  于 2021-07-24  发布在  Java
关注(0)|答案(0)|浏览(116)

我有一个spring方法访问不应该并发运行的数据库(写入和检查可能导致竞争条件)。一个方法可以一次运行,如果方法被多次调用(restapi是主要触发器),第一个示例应该持有锁,执行逻辑并释放锁,然后第二个示例将启动,依此类推。
由于实现分布式锁不是一个简单的任务,我认为必须有一个简单的解决方案,因为这似乎是一个非常普通的sql问题。我找到的解决办法,正是我要找的 sp_getapplock .
我在dbeaver中使用纯sql脚本对它进行了测试,它可以无缝地工作。第一个调用将获得状态为0的锁(无需等待即可授予),第二个调用将等待并获得状态为1的锁(等待后授予)。
但我无法将逻辑移动并重构为java代码。我尝试从java调用存储过程,但并发调用总是授予状态为0的锁。我错过了什么?我的想法可能是错的吗?我确保代码会在事务中运行。
是否有可能对存储过程的更多调用仍在同一事务中(因为top方法是 @Transactional )所以我马上去拿锁?如果是这样,在仍然有嵌套事务的情况下是否可以适当地避免这种情况?
我的代码:
sql语句

CREATE PROCEDURE [dbo].[test_lock]
AS
BEGIN
    BEGIN TRANSACTION

    DECLARE @result INT

    EXEC @result = sp_getapplock @Resource = 'TestLock', @LockMode = 'Exclusive', @LockOwner = 'Transaction'

    PRINT CONCAT('get - ', @result)

    WAITFOR DELAY '00:00:20'

    COMMIT TRANSACTION

    RETURN @result
END

java

public void testLockSP() throws PersistenceException {

    StoredProcedureQuery query = em.createStoredProcedureQuery("test_lock");

    query.execute();

    System.out.println(query.getFirstResult());
    System.out.println();
}
@Test
public void testConcurrent() throws Exception {

    Thread thread1 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                service.testLockSP();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    });

    Thread thread2 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                service.testLockSP();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    });

    thread1.start();
    thread2.start();

    thread1.join();
    thread2.join();
}

输出:

Hibernate: {call test_lock()}
Hibernate: {call test_lock()}
--waiting--
0
--waiting--
0

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题