снова multithreading
-
- Уже с Приветом
- Posts: 5669
- Joined: 13 Oct 2000 09:01
- Location: East Bay, CA
снова multithreading
Допустим юзер зарегистрировался на сайте и выполняется стейтмент
INSERT INTO users (userid,username)
VALUES((SELECT (MAX(userid)+1) FROM users),'name');
А если одновременно имеется несколько сессий и представим, что несколько юзеров нажали save одновременно? Как тут гарантировать уникальность выборки id?
В данном случае это снова JSP на Oracle. Речь идет о Model1, не о J2EE/MVC.
Спасибо,
Сабина
INSERT INTO users (userid,username)
VALUES((SELECT (MAX(userid)+1) FROM users),'name');
А если одновременно имеется несколько сессий и представим, что несколько юзеров нажали save одновременно? Как тут гарантировать уникальность выборки id?
В данном случае это снова JSP на Oracle. Речь идет о Model1, не о J2EE/MVC.
Спасибо,
Сабина
-
- Уже с Приветом
- Posts: 14006
- Joined: 17 Jun 2003 04:41
-
- Уже с Приветом
- Posts: 5669
- Joined: 13 Oct 2000 09:01
- Location: East Bay, CA
SBolgov wrote:Ээээ ... вообще-то, в Oracle специально для этого generators придуманы.
Это какие generators? Которые часть Oracle Designer - Client/Server generators?
Мне казалось тут какое более концептуальное решение должно быть. Ну скажем как это решается в том коде, которые generators генерируют?
Есть например решение использовать sequences вместо вставки subqueries для получения нового id. Но неужели только это? Ведь казалось бы речь идет о самой распространенной ситуации...
Я просто правда не знаю, можно чуть подробнее?
Сабина
-
- Уже с Приветом
- Posts: 664
- Joined: 05 Jun 2002 01:11
-
- Уже с Приветом
- Posts: 1102
- Joined: 16 Sep 2003 04:41
- Location: Out Of Blue
Re: снова multithreading
Sabina wrote:Как тут гарантировать уникальность выборки id?
Установить нужный transaction isolation level, например "read committed"
-
- Уже с Приветом
- Posts: 14006
- Joined: 17 Jun 2003 04:41
Пардон, я действительно обозвал sequences генераторами. Сорри, перепутал. Генераторами это называлось в Interbase.
А чем Вас sequences-то не устраивают?
Ситуация действительно самая распространённая, и в базе данных для этой ситуации сделан специальный механизм - sequences. Почему Вам так не хочется его использовать?
Subquery ещё и с точки производительности хуже. Сами подумайте - что дешевле: инкрементировать одну integer переменную или сделать запрос к таблице?
Sabina wrote:Есть например решение использовать sequences вместо вставки subqueries для получения нового id. Но неужели только это? Ведь казалось бы речь идет о самой распространенной ситуации...
А чем Вас sequences-то не устраивают?
Ситуация действительно самая распространённая, и в базе данных для этой ситуации сделан специальный механизм - sequences. Почему Вам так не хочется его использовать?
Subquery ещё и с точки производительности хуже. Сами подумайте - что дешевле: инкрементировать одну integer переменную или сделать запрос к таблице?
Не гоните, и не гонимы будете...
-
- Уже с Приветом
- Posts: 5669
- Joined: 13 Oct 2000 09:01
- Location: East Bay, CA
Re: снова multithreading
Blake wrote:Sabina wrote:Как тут гарантировать уникальность выборки id?
Установить нужный transaction isolation level, например "read committed"
Как тут описано?
Большое "пионерское" спасибо
А там кстати сказано
READ COMMITTED is the default isolation level in Oracle SQL
То есть получается и делать ничего не надо
Сабина
-
- Уже с Приветом
- Posts: 5669
- Joined: 13 Oct 2000 09:01
- Location: East Bay, CA
-
- Уже с Приветом
- Posts: 14006
- Joined: 17 Jun 2003 04:41
Sabina wrote:SBolgov wrote:А чем Вас sequences-то не устраивают?
Меня устраивают, просто хочется знать единственное ли это решение.
Разумеется, не единственное, но остальные имеют массу недостатков. А sequences, насколько я понимаю, были введены специально для того, чтобы решить данную проблему.
Не гоните, и не гонимы будете...
-
- Уже с Приветом
- Posts: 1102
- Joined: 16 Sep 2003 04:41
- Location: Out Of Blue
Re: снова multithreading
Sabina wrote:Большое "пионерское" спасибо
Большое "комсомольское" пожалуйста
-
- Уже с Приветом
- Posts: 13684
- Joined: 16 Jan 2001 10:01
Re: снова multithreading
Blake wrote:Установить нужный transaction isolation level, например "read committed"
А кто помнит какой он по умолчанию?
Мне сдается что "read committed" и есть...
-
- Уже с Приветом
- Posts: 5669
- Joined: 13 Oct 2000 09:01
- Location: East Bay, CA
Re: снова multithreading
Palych wrote:А кто помнит какой он по умолчанию?
Мне сдается что "read committed" и есть...
так точно (см ссылку выше)
Сабина
-
- Уже с Приветом
- Posts: 664
- Joined: 05 Jun 2002 01:11
Re: снова multithreading
Blake wrote:Sabina wrote:Как тут гарантировать уникальность выборки id?
Установить нужный transaction isolation level, например "read committed"
READ COMMITTED (as well as any other IL) won't ensure that 'id' will be unique in the above SQL. The provided statement, by itself, wil never work correctly.
VC
-
- Уже с Приветом
- Posts: 5669
- Joined: 13 Oct 2000 09:01
- Location: East Bay, CA
Re: снова multithreading
vc wrote:The provided statement, by itself, wil never work correctly.
VC
Never ?
Сабина
-
- Уже с Приветом
- Posts: 525
- Joined: 01 May 2002 20:29
- Location: CT->MA->TX->UT
Re: снова multithreading
Sabina wrote:Допустим юзер зарегистрировался на сайте и выполняется стейтмент
INSERT INTO users (userid,username)
VALUES((SELECT (MAX(userid)+1) FROM users),'name');
А если одновременно имеется несколько сессий и представим, что несколько юзеров нажали save одновременно? Как тут гарантировать уникальность выборки id?
В данном случае это снова JSP на Oracle. Речь идет о Model1, не о J2EE/MVC.
Спасибо,
Сабина
Change it to
INSERT INTO users (userid,username)
VALUES(your_sequence_name.nextval ,'name');
-
- Уже с Приветом
- Posts: 13684
- Joined: 16 Jan 2001 10:01
-
- Уже с Приветом
- Posts: 664
- Joined: 05 Jun 2002 01:11
Re: снова multithreading
Sabina wrote:vc wrote:The provided statement, by itself, wil never work correctly.
VC
Never ?
Сабина
You said it yourself in the original message. For concurrent transactions, the SQL will produce duplicates.
"..by itself, will never work" should be re-phrased as "..by itself, should *never* be used in order to guarantee unique ids". But that's nitpicking, really.
VC
-
- Уже с Приветом
- Posts: 1102
- Joined: 16 Sep 2003 04:41
- Location: Out Of Blue
Re: снова multithreading
Сабина, "set transaction isolation" действительно не поможет
Можно еще попробовать так, но это уже не совсем multithreading:
1)lock table USERS in exclusive mode;
2)INSERT INTO users (userid,username)
VALUES((SELECT (MAX(userid)+1) FROM users),'name');
3)commit; (rollback)
Можно еще попробовать так, но это уже не совсем multithreading:
1)lock table USERS in exclusive mode;
2)INSERT INTO users (userid,username)
VALUES((SELECT (MAX(userid)+1) FROM users),'name');
3)commit; (rollback)
-
- Уже с Приветом
- Posts: 14006
- Joined: 17 Jun 2003 04:41
Re: снова multithreading
Blake wrote:Можно еще попробовать так ...:
1)lock table USERS in exclusive mode;
Гм. И чего только ни придумают люди для того, чтобы всё-таки наступить на те грабли, которые разработчики предусмотрительно убрали с дороги.
Не гоните, и не гонимы будете...
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
Как уже было сказано, для ORACLE не существует стандартного решения этой задачи кроме как использование последовательностей или блокировка таблицы целиком. Любой другой вариант либо упрётся в ограничения модели изоляции транзакций, реализованной в ORACLE, либо потребует более, чем одного оператора SQL и обязательного наличия уникального индекса по userid (хотя такой индекс в любом случае полезен, но необязателен в случае других СУБД).
Cheers
-
- Уже с Приветом
- Posts: 664
- Joined: 05 Jun 2002 01:11
tengiz wrote:Как уже было сказано, для ORACLE не существует стандартного решения этой задачи кроме как использование последовательностей или блокировка таблицы целиком. Любой другой вариант либо упрётся в ограничения модели изоляции транзакций, реализованной в ORACLE, либо потребует более, чем одного оператора SQL и обязательного наличия уникального индекса по userid (хотя такой индекс в любом случае полезен, но необязателен в случае других СУБД).
Hello,
Long time, no hear, have you had a nice vacation ?
1. The sequence approach is a *standard* solution (see SQL'99's SQL/Foundation part), the alternative standard being the identity column. Oracle implements the sequence generator, SQL Server does the identity column, and DB2 has both.
2. From sheer curiosity, how one would implement a unique id generation in a blocking scheduler with a *single* SQL. Hints like UPDLOCK/TABLOCK and such are considered cheating ;)
VC
-
- Уже с Приветом
- Posts: 20297
- Joined: 01 Dec 2003 23:16
- Location: Russia->USA
Re: снова multithreading
Blake wrote:Sabina wrote:Как тут гарантировать уникальность выборки id?
Установить нужный transaction isolation level, например "read committed"
Имелся в виду read uncommitted?
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
vc wrote:Long time, no hear, have you had a nice vacation ?
Hope will have soon
The sequence approach is a *standard* solution
Так ведь я и сказал, что "не существует стандартного решения этой задачи кроме как использование последовательностей..."
From sheer curiosity, how one would implement a unique id generation in a blocking scheduler with a *single* SQL.
Использовать настоящий SERIALIZABLE (а не то, что в оракле так называется) с оригинальным запросом Сабины и никаких аномалий не будет.
Cheers
-
- Уже с Приветом
- Posts: 664
- Joined: 05 Jun 2002 01:11
tengiz wrote:...vc wrote:The sequence approach is a *standard* solution
Так ведь я и сказал, что "не существует стандартного решения этой задачи кроме как использование последовательностей..."
Ah, sorry my fault I mistakenly thought you'd meant that the sequence is a non-standard solution.
Regarding an Oracle solution without a sequence, true, *two* statements are required but *no* index is needed.
tengiz wrote:vc wrote:From sheer curiosity, how one would implement a unique id generation in a blocking scheduler with a *single* SQL.
Использовать настоящий SERIALIZABLE (а не то, что в оракле так называется) с оригинальным запросом Сабины и никаких аномалий не будет.
Oh, you meant this. I thought you'd had a neater trick up your sleeve ;) If one uses the true SERIALIZABLE, one should also be aware that the entire table will be locked, as the result of 'insert select max(id)+1', both for writes *and* reads. Here, SERIALIZABLE becomes SERIAL, nothing to be proud of, really. Essentially, the behaviour will be the same as in the 'solution' someone suggested for Oracle:
1. Lock the whole table
2. Do your stuff
.. no, the concurrency will be even worse, because in Oracle you can still read the locked table.
Also, it might be interesting to remind (I believe I mentioned the fact during one of our long discussions) that in version 7.x.x Oracle used to have the 'true' SERIALIZABLE whereby a table being selected from was automatically read-share locked thus preventing concurrent updates until the outstanding read transaction commits. More recent versions of Oracle retain this mode which can be enabled by setting a hidden parameter to 'true'. So technically speaking, in this mode, precisely the same *single* statement would work in the same way as it would in any locking scheduler SERIALIZABLE mode. Needless to say that the 'true' Oracle SERIALIZABLE' was not a success story due to abysmal concurrency.
In comparison to the 'true' Oracle serializable, the locking scheduler SERIALIZABLE provides more concurrency in some situations and less in others as you no doubt know. Neither is very suitable for heavily concurrent transactions. In the OP's situation, however, Oracle's 'true' SERIALIZABLE (not SNAPSHOT) would have an edge thanks to allowing concurrent reads.
All this discussion is of course purely theoretical because one should just use IDENTITY im SQL Server and SEQUENCE in Oracle and forget about possible but not concurrent alternatives.
Regards.
VC
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
vc wrote:I thought you'd had a neater trick up your sleeve If one uses the true SERIALIZABLE, one should also be aware that the entire table will be locked, as the result of 'insert select max(id)+1', both for writes *and* reads. Here, SERIALIZABLE becomes SERIAL, nothing to be proud of, really.
No, that's no true. If there is a unique key (othewise select max(id) would be painful enough by istelf for large tables) on id and the DBMS supports key-range locking plus the optimizer is smart enough you can get away with only a couple of key-ranges being locked.
Cheers