这个想法基本上是扩展some具有自定义功能的存储库。所以我得到了这个设置,它确实有效!
@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
。我确实阅读了文档和一些教程,但抽象的技术英语通常不容易理解。最后,我没有得到有效的解决方案,所以我手动添加了表锁定,效果很好。仍然更喜欢一种更像弹簧的方式来做到这一点。
1)您当前的设计也可能存在问题。这persist
不会立即在数据库中插入一行。当方法返回时,这会在事务提交时发生。
因此,您可以在实际插入之前解锁表:
// save
entityManager.persist(entity) // -> There is no INSERT at this point.
// unlock
entityManager.createNativeQuery("UNLOCK TABLES").executeUpdate()
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)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)