简体   繁体   English

如何使用 Spring Boot + Spring Data JPA 对悲观锁定进行单元测试

[英]How to unit test pessimistic locking with Spring Boot + Spring Data JPA

I want to test whether the FooRepository.lock() works, after someone called the lock() , others calling it should be wait.我想测试FooRepository.lock()是否有效,在有人调用lock()之后,其他人调用它应该等待。

The following is my best try, it doesn't work.以下是我最好的尝试,它不起作用。 I believe the reason is both entityManger and fooRepository are participating in the same transaction.我相信原因是entityMangerfooRepository都参与了同一个事务。

How to call the lock() from another transaction?如何从另一个事务中调用lock() Or any suggestion for unit-testing the pessimistic lock?或者对悲观锁进行单元测试的任何建议? Thanks!!谢谢!!

FooRepositoryTest: FooRepositoryTest:

package com.example.demo;

import java.util.UUID;

import javax.persistence.LockModeType;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataJpaTest
public class FooRepositoryTest {

    @Autowired
    private TestEntityManager entityManager;    

    @Autowired
    private FooRepository fooRepository;

    @Test
    public void lockTest() {
        // given
        Foo foo = new Foo();
        foo.setName("foo-name");

        UUID fooId = fooRepository.save(foo).getFooId();
        entityManager.flush();
        entityManager.clear();

        // when
        Foo savedFoo = fooRepository.findOne(fooId);
        fooRepository.lock(savedFoo);

        // then
        // I want something like this to be lock wait,
        // something to confirm the above fooRepository.lock() work
        entityManager.getEntityManager().lock(savedFoo, LockModeType.PESSIMISTIC_WRITE);
    }

}

class Foo: Foo类:

package com.example.demo;

import java.util.UUID;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Foo {  
    @Id
    @GeneratedValue
    private UUID fooId;

    private String name;

    public UUID getFooId() {
        return fooId;
    }

    public void setFooId(UUID fooId) {
        this.fooId = fooId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

class FooApplication: FooApplication 类:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FooApplication {

    public static void main(String[] args) {
        SpringApplication.run(FooApplication.class, args);
    }
}

class FooRepository:类 FooRepository:

package com.example.demo;

import java.util.UUID;

import org.springframework.data.jpa.repository.JpaRepository;

public interface FooRepository extends JpaRepository<Foo, UUID>, FooRepositoryCustom {  
}

class FooRepositoryCustom:类 FooRepositoryCustom:

package com.example.demo;

public interface FooRepositoryCustom {  
    public void lock(Foo foo);  
}

class FooRepositoryImpl: FooRepositoryImpl 类:

package com.example.demo;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;

import org.springframework.beans.factory.annotation.Autowired;

public class FooRepositoryImpl implements FooRepositoryCustom {

    @Autowired
    private EntityManager entityManager;

    @Override
    public void lock(Foo foo) {
        entityManager.lock(foo, LockModeType.PESSIMISTIC_WRITE);
    }   
}

You are getting unit testing wrong .你得到错误的单元测试。

You do not write unit test to exercise functionality implemented by some 3rd party framework.不会编写单元测试来执行某些 3rd 方框架实现的功能。 Unit tests are for your units!单元测试适用于您的单元!

In other words: you do not need to verify that locking works as expected.换句话说:您不需要验证锁定是否按预期工作。 Your unit does:您的单位可以:

entityManager.lock(foo, LockModeType.PESSIMISTIC_WRITE);

so the only thing you could consider testing here: making sure that the entity manager lock() method is called with the expected parameters.所以你可以考虑在这里测试的唯一一件事:确保使用预期的参数调用实体管理器lock()方法。

Meaning: verify that your code does use the framework as you think it should be used - but don't get into testing other peoples code!含义:验证您的代码确实使用了您认为应该使用的框架 - 但不要测试其他人的代码! You see - what would you do when your unit test shows that the framework is wrong ... you can't change that!你看 - 当你的单元测试表明框架是错误的时你会怎么做......你不能改变它! (sure, you can write a bug report then) (当然,你可以写一个错误报告然后)

Disclaimer: there might be special situations where you assume that some 3rd party product has a bug - then it might be very useful to write a unit test to test this assumption.免责声明:在某些特殊情况下,您可能会假设某些 3rd 方产品存在错误 - 那么编写单元测试来测试此假设可能非常有用。 So that you can later run the unit test against a new version of that product to see if the bug is still present.这样您以后就可以针对该产品的新版本运行单元测试,以查看错误是否仍然存在。

Testing pessimistic locking handling with an integration test is important (may I say mandatory?) for two reasons:使用集成测试测试悲观锁定处理很重要(我可以说是强制性的吗?),原因有两个:

  • There is a good chance that the LockTimeout parameter is not correctly configured (by Oracle and PostgreSQL it is by default infinite time) and this could have a dramatic impact on the stability/performance of the system in production; LockTimeout 参数很可能没有正确配置(Oracle 和 PostgreSQL 默认为无限时间),这可能会对生产中系统的稳定性/性能产生巨大影响;
  • The JPA implementation for pessimistic locking by most RDBMS is very limited because the 6 internal LockTimeout parameters differ;大多数 RDBMS 对悲观锁定的 JPA 实现非常有限,因为 6 个内部 LockTimeout 参数不同; Testing against an in-memory database only could be not enough and would require special considerations.仅针对内存数据库进行测试是不够的,需要特别考虑。

In the blog post Testing Pessimistic Locking Handling With SpringBoot and JPA you could:在博客文章使用 SpringBoot 和 JPA 测试悲观锁定处理中,您可以:

  • Read more about pessimistic locking handling;阅读有关悲观锁定处理的更多信息;
  • And you could find GitHub examples for testing against Oracle, PostgreSQL, MySQL and Apache Derby.您可以在GitHub 上找到针对 Oracle、PostgreSQL、MySQL 和 Apache Derby 进行测试的示例

🔔 The Spring Framework is used only as an example. 🔔 Spring 框架仅用作示例。 You could easly adapt the tests for every other framework.您可以轻松地为每个其他框架调整测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM