背景
我有很多不同的“事物”(特定于域的项目/实体/主题),这些东西对“事物”所有者(人类)可见。所有者将用数字标识他们的“事物”。我要显示一个较小的数字(最好是从1开始的序列),而不是显示一个较大的“随机”数字,这对人类来说比较容易。业主很乐于谈论“我的富人37”和“她的酒吧128”。那里的“序列”可以有间隔,但附加的数目必须在“事物”实例的生存期内保持不变。因此,我需要一种生成“事物”
+所有者特定ID(当前称为“可见ID”)的方法。
“事物” +所有者组合的数量为10k +。当前无法动态生成新的“事物”,但所有者可以生成。
每个所有者一个“事物”实例的数量相对较小,每个所有者大约数十个,但是没有可以从业务规则中得出的硬性上限。经常创建和删除新的“事物”实例。
考虑的选项
我在一个SO问题Oracle分区序列中找到了一个很好的讨论,该问题几乎解决了我所遇到的相同问题。
到目前为止,我已经考虑了以下选项:
max(visible_id) + 1
但是我们会遇到正常的并发问题,所以这是不可行的。问题
还有其他解决此问题的方法,还是应该开始动态创建序列?如果序列是答案,请详细说明可能存在的陷阱(例如DDL中的隐式提交)。
我对Oracle 11gR2和12c解决方案都感兴趣(如果它们不同)。
伪代码来说明问题
create table foo (
id number primary key -- the key for computers
,owner_id number
,visible_id number -- the key for humans
,data_ varchar2(20)
);
create constraint foo_u1 unique foo(owner_id, visible_id);
-- primary key sequence
create sequence foo_id_seq;
insert into foo values(
foo_id_seq.nextval
,1
,1 -- what to put here ?
,'lorem ipsum'
);
insert into foo values(
foo_id_seq.nextval
,2
,1 -- what to put here ?
,'dolor sit amet'
);
select visible_id, data_ from foo where owner = 2 order by visible_id;
由于差距尚可,因此您应该实现“选项2”的变体。允许间隔意味着您可以快速完成同步:竞争的会话仅检查并继续,而不必等待其他会话是否提交或回滚。
如果Oracle提供了一个INSERT INTO..NOWAIT
选项,这将很容易。实际上,我可能会参与其中DBMS_LOCK
。这是我对您的API外观的看法。
它对您拥有的最大可见ID做出了一些假设,因为您是在原始帖子中做出这些假设的。
CREATE OR REPLACE PACKAGE foo_api AS
PROCEDURE create_foo (p_owner_id NUMBER, p_data VARCHAR2);
END foo_api;
CREATE OR REPLACE PACKAGE BODY foo_api AS
-- We need to call allocate_unique in an autonomous transaction because
-- it commits and the calling program may not want to commit at this time
FUNCTION get_lock_handle (p_owner_id NUMBER, p_visible_id NUMBER)
RETURN VARCHAR2 IS
PRAGMA AUTONOMOUS_TRANSACTION;
l_lock_handle VARCHAR2 (128);
BEGIN
DBMS_LOCK.allocate_unique (
lockname => 'INSERT_FOO_' || p_owner_id || '_' || p_visible_id,
lockhandle => l_lock_handle
);
COMMIT;
RETURN l_lock_handle;
END;
PROCEDURE create_foo (p_owner_id NUMBER, p_data VARCHAR2) IS
-- This is the highest visible ID you'd ever want.
c_max_visible_id NUMBER := 1000;
BEGIN
<<id_loop>>
FOR r_available_ids IN (SELECT a.visible_id
FROM (SELECT ROWNUM visible_id
FROM DUAL
CONNECT BY ROWNUM <= c_max_visible_id) a
LEFT JOIN foo
ON foo.owner_id = p_owner_id
AND foo.visible_id = a.visible_id
WHERE foo.visible_id IS NULL) LOOP
-- We found a gap
-- We could try to insert into it. If another session has already done so and
-- committed, we'll get an ORA-00001. If another session has already done so but not
-- yet committed, we'll wait. And waiting is bad.
-- We'd like an INSERT...NO WAIT, but Oracle doesn't provide that.
-- Since this is the official API for creating foos and we have good application
-- design to ensure that foos are not created outside this API, we'll manage
-- the concurrency ourselves.
--
-- Try to acquire a user lock on the key we're going to try an insert.
DECLARE
l_lock_handle VARCHAR2 (128);
l_lock_result NUMBER;
l_seconds_to_wait NUMBER := 21600;
BEGIN
l_lock_handle := get_lock_handle (
p_owner_id => p_owner_id,
p_visible_id => r_available_ids.visible_id
);
l_lock_result := DBMS_LOCK.request (lockhandle => l_lock_handle,
lockmode => DBMS_LOCK.x_mode,
timeout => 0, -- Do not wait
release_on_commit => TRUE);
IF l_lock_result = 1 THEN
-- 1 => Timeout -- this could happen.
-- In this case, we want to move onto the next available ID.
CONTINUE id_loop;
END IF;
IF l_lock_result = 2 THEN
-- 2 => Deadlock (this should never happen, but scream if it does).
raise_application_error (
-20001,
'A deadlock occurred while trying to acquire Foo creation lock for '
|| p_owner_id
|| '_'
|| r_available_ids.visible_id
|| '. This is a programming error.');
END IF;
IF l_lock_result = 3 THEN
-- 3 => Parameter error (this should never happen, but scream if it does).
raise_application_error (
-20001,
'A parameter error occurred while trying to acquire Foo creation lock for '
|| p_owner_id
|| '_'
|| r_available_ids.visible_id
|| '. This is a programming error.');
END IF;
IF l_lock_result = 4 THEN
-- 4 => Already own lock (this should never happen, but scream if it does).
raise_application_error (
-20001,
'Attempted to create a Foo creation lock and found lock already held by session for '
|| p_owner_id
|| '_'
|| r_available_ids.visible_id
|| '. This is a programming error.');
END IF;
IF l_lock_result = 5 THEN
-- 5 => Illegal lock handle (this should never happen, but scream if it does).
raise_application_error (
-20001,
'An illegal lock handle error occurred while trying to acquire Foo creation lock for '
|| p_owner_id
|| '_'
|| r_available_ids.visible_id
|| '. This is a programming error.');
END IF;
END;
-- If we get here, we have an exclusive lock on the owner_id / visible_id
-- combination. Attempt the insert
BEGIN
INSERT INTO foo (id,
owner_id,
visible_id,
data_)
VALUES (foo_id_seq.NEXTVAL,
p_owner_id,
r_available_ids.visible_id,
p_data);
-- If we get here, we are done.
EXIT id_loop;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
-- Unfortunately, if this happened, we would have waited until the competing
-- session committed or rolled back. But the only way it
-- could have happened if the competing session did not use our API to create
-- or update the foo.
-- TODO: Do something to log or alert a programmer that this has happened,
-- but don't fail.
CONTINUE id_loop;
END;
END LOOP;
END create_foo;
END foo_api;
以下是我要保存(创建/更新)的实体模型: 有两种方法可以更新此实体: < li >第一个更新除< code>notified属性以外的所有属性的人 < li >第二个更新< code>notified属性的仅 有没有办法告诉Hibernate忽略某个特定方法的某些字段?我需要创建两个不同的特定dao方法吗?我是否需要为经典的< code>save方法保留< code>updatable=false
我正在为我的新项目使用android room持久性库。我想更新表的某些字段。我在我的中尝试过- 但是,当我尝试使用此方法进行更新时,它会更新实体的每个字段,在这些字段中,它与tour对象的主键值相匹配。我已使用 它正在工作,但在我的情况下会有很多查询,因为我的实体中有很多字段。我想知道如何更新某些字段(不是全部),如,id=1;(id是自动生成主键)。
问题内容: 我可以为一个实体使用多个序列生成器吗? 问题答案: 你不能。该生成器仅适用于标识符列。 确保使用脚本(例如)创建此序列: 然后使用如下映射:
首先,我已经阅读了Hibernate——一个包含多个实体的表?。 然而,我希望将两个实体映射到同一个表,但我希望它们都是实体,我可以从中选择。我的意思是: 一个表:人(id、姓名、出生日期、城市、街道、邮政编码)。 两个实体:人(id、name、dateOfBirth)、地址(id、城市、街道、邮政编码)。 实体之间是1:1的关系,但数据库中仍然是1个表。 如果我在上面的链接中使用建议的解决方案(
itemdao.java posDatabase.java invoice.java 错误:错误:查询返回的列在com.example.qrreceipt.Item中没有字段[item_id,price],即使它们被注释为非空或原语。查询返回的列:[invoice_id,terminal_no,cashier_name]