【问题标题】:How to LOCK TABLE ... do stuff ... UNLOCK TABLE with Spring Boot?如何锁定表...做事...解锁表与 Spring Boot?
【发布时间】:2019-06-10 16:21:45
【问题描述】:

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

@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)
    }
}

我会怎样做才能更像春天?

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

【问题讨论】:

    标签: java spring spring-boot jpa spring-data-jpa


    【解决方案1】:

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

    所以你在实际插入之前解锁表:

        // save
        entityManager.persist(entity) // -> There is no INSERT at this point.
    
        // unlock
        entityManager.createNativeQuery("UNLOCK TABLES").executeUpdate()
    

    2) 回到如何只使用 JPA 而不使用 native(它仍然需要一些解决方法,因为默认情况下不支持):

        // 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)
    

    【讨论】:

    • 2) 这不会锁定单个实体而不是孔表吗?
    • 它应该锁定整个表。取决于持久性提供者,但它应该
    • 我玩过。我不认为它会锁定整个表。当 ID 为 1 的实体丢失时,表不会被锁定。因此,当每个线程都锁定一个 id 为 1 的现有实体时,这基本上就是一个伪整表锁定。
    • 解锁表部分不应该在 finally 块中吗?
    猜你喜欢
    • 2011-05-12
    • 2019-07-29
    • 1970-01-01
    • 2014-08-07
    • 1970-01-01
    • 2010-10-16
    • 2021-12-15
    • 2019-01-04
    • 1970-01-01
    相关资源
    最近更新 更多