トップページ⇒tech
62コメント28KB

ASP+SQL Serverで切実に困ってます。

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
自分で本やWebを調べたんですけどわかんなくて・・・
たぶんすっごい基本的なことだと思うんで知ってる人いたらタスケテ。

ASP+MS SQL Serverで作ったWebのサービスに異常発生。
調べてみたらユニークでなきゃいけないIDがかぶってました。
どうやら
1.一番大きいIDを引っ張ってくる。
↓
2.それに+1する
↓
3.+1したIDをつけてINSERT。

っていうところで1→3が終わる前に他のユーザが1の処理を
はじめるとIDがかぶるってことがわかりました。
(ためしに自分で2台同時にボタンおしたらかぶりました)

会社でほかにわかる人がいないので凄い基本っぽい気がする
この問題が解決できません(涙
ロックとかトランザクションって調べたんですけどいまいち意味がわかってない
せいかうまくいきません。
17日の正午までメンテナンス中っていうページに差し替えて
しのいであるんだけどこのままじゃ・・・。
0032デフォルトの名無しさんNGNG
>>27
ASP の VBScript には On Error GoTo ないぞ(正確には On Error GoTo 0,
On Error Resume Next だけ使える)。
003327NGNG
>>32
そーか、ごめん。
IIS+ASPにはもう何年も触ってないのに適当なこと書いちゃった。

そうすると、この場合のエラー処理はどうするんだろう。On Error Resume Next
しておいて、ConnectionオブジェクトのErrorsプロパティをチェックすれば
できるのかな?
0034デフォルトの名無しさんNGNG
>>27
つーか、そんな枝葉じゃなくて、根本的なトコロが間違ってるのよ。
0035デフォルトの名無しさんNGNG
>>27
まじで、痛すぎるよ。
カキコ控えてROMに徹したほうが身のためだよ。
00361NGNG
ええとIDENTITYで重複だめにするとエラーに行くんすよね。
先の処理をまっててくれる⇒ROCKにしたい所存。

↑こういう現状です。

>9
で言ってるようにWITH(UPDLOCK)ってのがつかえないんすが・・・

>Error401
調べ中に見つけたんすけどロールバックされたら@@IDENTITYは元に戻らないそうです。
0037デフォルトの名無しさんNGNG
なぜ、別に一個 1rowだけのMAXナンバーを格納したTableを作らんの?
そして、そのtableに
update dummy set dummy = max + 1 where dummy = max;
としてupdateを発行しないの?他のセッションが同時期におなじupdate文を
発行したなら、dummy = maxのrowは存在しなくなるから変更は行われない。
変更行がなかった場合にはもう一度maxの取得をして変更できるまで繰り返す。
update文の実行はアトミックであることが保証されてるからmax + 1もアトミックな
値が返るぞ。
0038デフォルトの名無しさんNGNG
>>30 >>31 >>35
人を批判する前に自分の考えを示しな。
27の方が多少なりともえらいぞ。
ちなみにおれはASP使いじゃないからしらん。
0039Error401NGNG
>>37
うーん、update dummy文が1文1トランザクションだとすると、連番保証が
なくなるので、IDENTITYを使うのと変わらないし、
更新対象のupdate文と同じトランザクションに入れるのなら、
select max(id) + 1と変わらない気がするんですけど・・・。

>>38
えーと、>>27のコードは、本質的に>>1となんら変わりがないので
批判されてるんじゃないかと思います。
解決法はすでに出尽くしてると思うし。
0040デフォルトの名無しさんNGNG
>>38
ASPとかそうゆう問題じゃないんだよ。
それがわからないお前も逝ってよし。
さすが、Error401氏
004127NGNG
27です。あがってたとは知りませんでした。

>>39
すいません。後で気が付いたんですが、その通りですね。

それで、昔同じようなことをしたのを思い出しました。そのときの解決法は
>>37のようにMAX値保存テーブルを作成し、ストアドプロシージャで

1. 現在のMAX値を更新用カーソルで取得する
2. インクリメントしたMAX値をそのカーソルを使用して更新する

を1トランザクションで実行し、成功したら更新したMAX値を返す、という方法を
取りました。
00421NGNG
>37 >39 >27
ありがとうございます。なんとなくわかってきたかも。
発番用のテーブルを用意するってのはそういうことだったんすね。13

そんで今わからないのがその重複しちゃ困るIDで同時に
もう1個のテーブルをINSERTまたはUPDATEしてるんですけど
「そのカーソルだと複数にまたがったトランザクションできません」
みたいなエラーがでます。
(ロックタイプ、カーソルは 3.3 です。)
0043便乗質問でスミマセンNGNG
すみません。SELECT文で教えてください。
ある条件で、11件目から5件のレコードを取り出す場合、

PostgreSQLなら
SELECT * FROM syohin WHERE tanka < 10000 OFFSET 10 LIMIT 5;

MySQLなら、
SELECT * FROM syohin WHERE tanka < 10000 LIMIT 10,5;

MS-SQL2000Serverの場合はどうしたらいいんでしょう?
いろいろ調べたのですが分かりません。
0044便乗質問でスミマセンNGNG
すみません。SELECT文で教えてください。
ある条件で、11件目から5件のレコードを取り出す場合、

PostgreSQLなら
SELECT * FROM syohin WHERE tanka < 10000 OFFSET 10 LIMIT 5;

MySQLなら、
SELECT * FROM syohin WHERE tanka < 10000 LIMIT 10,5;

Oracle8の場合はどうしたらいいんでしょう?
いろいろ調べたのですが分かりません。
ちなみに、
WHERE ROWNUM BETWEEN 11 AND 15
はダメでした。
0045 NGNG
おお!祭りか?
マルチスレッド知らない厨房がサーバーサイドやっちまったのかWW
0046 NGNG
セマフォで合ってるよん。
0047 NGNG
SELECT * FOR UPDATE //ロック セマフォね
〜
UPDATE //ロック解除
だったような気がする。
0048 NGNG
COMMITだったような気もする。
0049デフォルトの名無しさんNGNG
>19
2 INSERT 直後に @@IDENTITY で番号を取得。
のコードの書き方教えて
0050 NGNG
>>44,45
WHERE ... AND (ROWNUM >10) AND (ROWNUM <16)
だったような気がする。
0051デフォルトの名無しさんNGNG
37
もうちょっとくわしく説明して下さい

なぜ、別に一個 1rowだけのMAXナンバーを格納したTableを作らんの?
そして、そのtableに
update dummy set dummy = max + 1 where dummy = max;
としてupdateを発行しないの?他のセッションが同時期におなじupdate文を
発行したなら、dummy = maxのrowは存在しなくなるから変更は行われない。
変更行がなかった場合にはもう一度maxの取得をして変更できるまで繰り返す。
update文の実行はアトミックであることが保証されてるからmax + 1もアトミックな
値が返るぞ。
005243NGNG
>45
それはつまり、マルチスレッドというもので解決できるのでしょうか?
ありがとうございます。後は自分で調べてみます。
0053デフォルトの名無しさんNGNG
MS SQL Serverなら、フィールドの属性にindex(1,1)とか指定すれば同じ様な連番は振れたはず。
しかし、落とし穴があって、システムが異常終了するとこの連番が狂うので、DBCCで修正してやらないといけない
0054デフォルトの名無しさんNGNG
37
他のセッションが同時期におなじupdate文を
発行したなら、dummy = maxのrowは存在しなくなるから変更は行われない

この理由がよくわからないのですが
005527NGNG
>>50
Oracle の ROWNUM って、使える演算子は <, <= の二つだけだぜ。
0056仕様書無しさんNGNG
>>54

ふたつのセッションで同じ値の max (仮に10とする) を取得してしまったとしても、
そのうちのひとつのセッションで、先に dummy = max + 1 ( dummy = 10 + 1 ) に
書き換えれば、dummy = 10 の行は存在しなくなるでしょ。
もうひとつのセッションで dummy = 10 の行への書き込みを試みても、そんな行は
もうないから、書き込みは行えないというわけ。
0057デフォルトの名無しさんNGNG
すみません、教えてください。ASPからMSDEにアクセスしているのですが、DBのデータが大量にあり、
複数のクライアントからアクセスすると、「容量を超えていたため、
新規トランザクションを作成できません。」というエラーが返ってきます。
そこで、もしMSDEのトランザクション領域(デフォルト)のサイズをご存知の方が
いらっしゃいましたら、教えていただけないでしょうか?
よろしくお願いします。
0058縞栗鼠(シマリス)の親方NGNG
中央高等学院の従業員「西部」が女子トイレに闖入し
汚物入れを物色して女子生徒の使用済みタンポン・ナプキン等を
個人的に収集しているというのは事実。

中央高等学院では
生徒及びその保護者の個人情報を名簿図書館等に売却しています。
中央高等学院 http://chs-f.com/index.html 中央高等学院福岡校
http://www.chuo-school.ac/
0059名無しさん@EmacsNGNG
>>44
FAQなのレス。

(>50だと期待する結果にならんと思われ。
WHERE句のROWNUMは条件が入るとみんな偽になってしまうので。)

11件目から5件ってことは11件目から15件目を取得すればいいので、

SELECT * FROM syohin WHERE tanka < 10000 AND ROWNUM <= 15
MINUS
SELECT * FROM syohin WHERE tanka < 10000 AND ROWNUM < 11

つまり、15件以下のデータから10件以下をマイナスすればいいのレス。
0060名無しさん@EmacsNGNG
ごめん。ageてしまった...

あと、間違ってた...鬱だ...

最後は ROWNUM < 11 ですわな...
0061デフォルトの名無しさんNGNG
こういうのは、MAX+1を取ってくるんじゃなくて、SELECTのタイミングで
MAX+1に適当なダミーデータを放り込んでおいて、INSERTの変わりにUPDATE
すべきかと思われ。

SQL*Serverにあるのかどうか知らんが、SWQENCEつかうのが一番いいとおもわれ。
0062デフォルトの名無しさんNGNG
>>1
方法1.1〜3をBEGIN TRANSACTIONとCOMMITで囲む。(これにより排他がかかる)
方法2.ユニークインデックスにして、重複エラー時は適当な時間をおいてリトライさせる。
方法3.1〜2を3のトリガー処理に書きSQL分を一つにする。トリガー処理は一意であるのでOKになる。

■ このスレッドは過去ログ倉庫に格納されています