我需要在Employee表中插入员工我想要的是避免重复插入,即如果thwo线程试图同时插入同一个员工然后上次交易 应该失败。例如,如果first_name和hire_date对于两个员工(来自两个线程的同一员工)是相同的,那么最后一个事务就失败了。
方法1: - 第一种方法我可以考虑将约束置于列级别(如first_name和hire_date上的组合唯一约束)或查询检查是否 员工存在抛出错误(我相信它可以通过PL / SQL实现)
方法2: - 可以在java级别完成,就像创建一个首先检查员工是否存在然后抛出错误的方法一样。在这种情况下,我需要使方法scynchronized(或 同步块)但它会影响性能,它也会不必要地持有其他交易。有没有办法我可以把锁(重入锁)或使用基于名称/ hiredate的同步方法,以便只有那些具有相同名称和雇用的特定交易被搁置
public void save(Employee emp){
//hibernate api to save
}
我认为方法1应该是首选,因为它简单易行。对 ?即使是,我想知道它是否可以在java级别有效处理?
答案 0 :(得分:1)
我想要的是避免重复插入
和
但它会影响性能,它也会不必要地持有其他交易
因此,您需要高度并发的插入,以确保没有重复。
无论是在Java中还是在数据库中执行此操作,以 方式避免重复插入都是序列化(或者说,同步)。也就是说,让一个事务等待另一个事务。
如果您对密钥值创建PRIMARY KEY
或UNIQUE
约束,Oracle数据库将自动为您执行此操作。不重复的同时插入不会干扰或等待彼此。但是,如果两个会话同时尝试重复插入,则第二个会话将等到第一个完成。如果第一个会话通过COMMIT
完成,那么第二个事务将失败并且索引违例时会出现重复键。如果第一个会话通过ROLLBACK
完成,则第二个交易将成功完成。
您也可以在Java中执行类似的操作,但问题是您需要一个可供所有会话访问的锁定机制。 synchronize
和类似的替代方案仅在所有会话都在同一JVM中运行时才有效。
此外,在Java中,最大化并发和最小化等待的关键是仅等待实际的重复。您可以通过对传入的键值进行散列,然后仅对该散列进行同步来实现与此接近的效果。也就是说,例如,将65,536个对象放入列表中。然后,当插入想要发生时,将传入的键值散列为1到65536之间的数字。然后从列表中获取该对象并对其进行同步。当然,您也可以同步实际的键值,但哈希通常一样好,并且可以更容易使用,特别是如果传入的键值是笨拙或敏感的。
大家都说过,这绝对应该在数据库中使用表上的简单PRIMARY KEY
约束和适当的错误处理来完成。
答案 1 :(得分:0)
使用数据库的主要原因之一是他们给予一致性。
您正在志愿将部分责任重新纳入您的申请中。这听起来像是错误的做法。相反,您应该准确研究数据库提供的功能;并尝试“尽可能多地使用它们”。
从这个意义上说,你试图在错误的层面上解决问题。
答案 2 :(得分:0)
Pseudo Code :
void save (Employee emp){
if(!isEmployeeExist(emp)){
//Hibernate api to save
}
}
boolean isEmployeeExist(Employee emp){
// build and run query for finding the employee
return true; //if employee exists else return false
}
答案 3 :(得分:0)
好问题。在这种情况下,我强烈建议使用MERGE(在单个DML中使用INSERT和UPDATE)。让Oracle处理txn并锁定。在你的情况下,这是最好的。
您应该创建主键,唯一约束(方法1),无论保留数据完整性的任何解决方案。
- 示例声明
MERGE INTO employees e
USING (SELECT * FROM hr_records) h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
答案 4 :(得分:0)
由于尚未插入行,因此隔离级别(例如READ_COMMITED / REPEATABLE_READ)将不适用于它们。
最好是应用数据库约束(唯一),如果该约束不存在,则在多节点设置中 您也无法通过Java锁来实现它。作为请求可以去任何节点。 因此,在这种情况下,我们需要具有分布式锁定类型的功能。 我们可以创建一个表锁,在该表锁中,我们可以为每个表定义一个节点或只能插入一个集合。 例如: 表名,已锁定 emp,“ N”
没有任何代码可以在此行上获得READ_COMMITED并尝试将Lock_acuired更新为'Y' 因此,其他线程或其他节点中的任何其他代码将无法继续进行,并且只有在释放先前的锁定时才会给出锁定。 这将确保可以避免重复的高度并发的系统,但是这会遇到可校准性问题。因此,请相应地确定要达到的目标。