如何锁定表...做事...使用 Spring Boot 解锁表?

Tom*_*mes 6 java spring jpa spring-data-jpa spring-boot

这个想法基本上是用自定义功能扩展一些存储库。所以我得到了这个设置,它确实有效!

@MappedSuperclass
abstract class MyBaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Int = 0

    var eid: Int = 0

}

interface MyRepository<T : MyBaseEntity> {

    @Transactional
    fun saveInsert(entity: T): Optional<T>
}

open class MyRepositoryImpl<T : MyBaseEntity> : MyRepository<T> {

    @Autowired
    private lateinit var entityManager: EntityManager

    @Transactional
    override fun saveInsert(entity: T): Optional<T> {

        // lock table
        entityManager.createNativeQuery("LOCK TABLE myTable WRITE").executeUpdate()

        // get current max EID
        val result = entityManager.createNativeQuery("SELECT MAX(eid) FROM myTable LIMIT 1").singleResult as? Int ?: 0

        // set entities EID with incremented result
        entity.eid = result + 1

        // test if table is locked. sending manually 2-3 POST requests to REST
        Thread.sleep(5000)

        // save
        entityManager.persist(entity)

        // unlock
        entityManager.createNativeQuery("UNLOCK TABLES").executeUpdate()

        return Optional.of(entity)
    }
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能做得更像春天呢?

起初,我以为它@Transactional会做锁定和解锁的事情。我尝试了几个附加参数和@Lock. 我确实阅读了文档和一些教程,但抽象的技术英语通常不容易理解。最后,我没有得到有效的解决方案,所以我手动添加了表锁定,效果很好。仍然更喜欢一种更像弹簧的方式来做到这一点。

Mac*_*ski 0

1)您当前的设计也可能存在问题。不会persist立即在数据库中插入一行。当方法返回时,这会在事务提交时发生。

因此,您可以在实际插入之前解锁表:

    // save
    entityManager.persist(entity) // -> There is no INSERT at this point.

    // unlock
    entityManager.createNativeQuery("UNLOCK TABLES").executeUpdate()
Run Code Online (Sandbox Code Playgroud)

2)回到如何仅使用 JPA 而不使用本机来执行此操作(它仍然需要一些解决方法,因为默认情况下不支持它):

    // lock table by loading one existing entity and setting the LockModeType
    Entity lockedEntity = entityManager.find(Entity.class, 1, LockModeType.PESSIMISTIC_WRITE);

    // get current max EID, TRY NOT TO USE NATIVE QUERY HERE

    // set entities EID with incremented result

    // save
    entityManager.persist(entity)
    entityManager.flush() // -> Force an actual INSERT

    // unlock by passing the previous entity
    entityManager.lock(lockedEntity, LockModeType.NONE)
Run Code Online (Sandbox Code Playgroud)

  • 我到处玩。我不认为它会锁定整个表。当 ID 为 1 的实体丢失时,表不会被锁定。因此,当每个线程锁定 id 为 1 的现有实体时,这基本上就是伪全表锁。 (2认同)