ASP+SQL Serverで切実に困ってます。
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
NGNGたぶんすっごい基本的なことだと思うんで知ってる人いたらタスケテ。
ASP+MS SQL Serverで作ったWebのサービスに異常発生。
調べてみたらユニークでなきゃいけないIDがかぶってました。
どうやら
1.一番大きいIDを引っ張ってくる。
↓
2.それに+1する
↓
3.+1したIDをつけてINSERT。
っていうところで1→3が終わる前に他のユーザが1の処理を
はじめるとIDがかぶるってことがわかりました。
(ためしに自分で2台同時にボタンおしたらかぶりました)
会社でほかにわかる人がいないので凄い基本っぽい気がする
この問題が解決できません(涙
ロックとかトランザクションって調べたんですけどいまいち意味がわかってない
せいかうまくいきません。
17日の正午までメンテナンス中っていうページに差し替えて
しのいであるんだけどこのままじゃ・・・。
0002デフォルトの名無しさん
NGNG処理1の前に
conn.BeginTrans
して、
処理1-3が成功したら
conn.CommitTrans
どこかで失敗したら
conn.RollbackTrans
する。(connはConnectionオブジェクト)
でもちゃんと勉強した方がいいよ。トランザクションも知らずにDB
アプリを組むのは無謀ですよ。
0003デフォルトの名無しさん
NGNG上のような感じにやってるんですが、その「失敗したか」
っていうのをCommitTransする前にどうやって判断したらいいかがわからなくて・・・。
00041
NGNGSQL = "SELECT TOP 1 bk_id FROM book ORDER BY bk_id DESC"
SET RS = CON.Execute(SQL)
If RS.EOF Then
newbk_id = 1
Else
newbk_id = RS("bk_id")+1
End If
SET rsInsert = Server.CreateObject("ADODB.Recordset")
rsInsert.Open "book", CON, 3, 3
rsInsert.AddNew
rsInsert("bk_id") = newbk_id
rsInsert.Update
rsInsert.Close
SQL = "SELECT TOP 1 bk_id FROM book ORDER BY bk_id DESC"
SET RS2 = CON.Execute(SQL)
if RS2("bk_id")+1 = newbk_id then
CON.CommitTrans
else
CON.RollBackTrans
response.redirect "error.asp"
end if
こんな感じなんですがものすごくだめな気がします>オレ
だれかお助けを・・・もちろん土日も会社です(今も)
うっ
0005デフォルトの名無しさん
NGNGhttp://www.acc.gr.jp/wwwdata/pinsql/19981228/836.html
本当は、設計が悪いといいたけどそういわれてもこまるでしょう。
bookをテーブルロックしたら副作用が出るかもしれないけど
その辺は全体をみないとわからないからとりあえず。
0006デフォルトの名無しさん
NGNGApplication.Lock
ストアド実行
Application.Unlock
でダメ?俺もASP知らないけど、カウンタのサンプルでApplication.Lockって使ってたよ
0007<>
NGNG> この問題が解決できません(涙
どんな会社だよ。本当か?
教えてもいいけどさ、つか他の人がロジックまで丁寧に書いてくれてる
からそれ以上言わないけどさ、
根本的に、誰も排他制御も知らん会社で仕事してる事が一番の問題
な気がするぞ。転職すれ。
君のコードで言うと
> SET RS2 = CON.Execute(SQL)
これをやったときに、RS2のプロパティかメソッドで何らかエラーが
拾えるはずだが(調べるのメンドイからそこは割愛するが、ワリィ)
その結果をによってCommitTransもしくはRollback
って感じじゃないのかね?
0008デフォルトの名無しさん
NGNG他がオープン中のときは、処理が終わるまで待たされるようになる。
sSQL = "SELECT TOP 1 bk_id FROM book ORDER BY bk_id DESC"
Call rs.Open("book", CON, 3, 2)
If rs.EOF = True Then
lNewId = 1
Else
lNewId = rs("bk_id") + 1
End If
rs.AddNew
rs("bk_id") = lNewId
rs.Update
rs.Close
SQLServerなど信用できんというならば、ファイルロックを使うかな。
排他でオープンしようとするとエラーになるのでOnErrorResumeNextでErr.Number
をチェックして、オープンできるまでぐるぐる繰り返す。
OSのファイル処理など信用できんというならば、、、知らん。
0009
NGNGSELECT MAX(bk_id) FROM book WITH(ROWLOCK)
0010
NGNG00111
NGNG「10人同時に押したら10人分まつのか!」っていわれてやり直しに・・・。
結局IDがかぶっててもいいように作り変えることになりました。
なんか負けた感が強いです。
0012デフォルトの名無しさん
NGNGDドラゴン
Bボール
ですか?クリリンとか
0013デフォルトの名無しさん
NGNG上司も上司に言い切られるあなたも逝って良し。
>>10
DBの人というかVBの人かな。俺も良く分からん。
ミューテックスとかセマフォとかVBSから使えるのだろうか。
Application.Lockてのがそれっぽいですが。
MSDNより引用
> <%
> Application.Lock
> Application("Counter") = Application("Counter") + 1
> Application.UnLock
> %>
> Lock すると、他のユーザーからの操作をロックし、
> そのアクセスしたユーザーだけが値を変更でき、
> UnLock すると、ロック状態を解除できるというわけです。
> こうすることで、ユーザによる値の変更を競合なく
> おこなっていくことができるようになるわけですね
0014
NGNGアクセスであるやつ。
0015デフォルトの名無しさん
NGNGIDENTITYですな。
>>10
セマフォ? なぜここでセマフォが?
単なるトランザクション処理でしょ。
00161
NGNGその方法、ズシリときた!とてもいい感じがします。
次からそれでいこう。
>9
ROWLOCKってのはいつからいつまでLOCKするんですか?
もしかして
SELECT MAX(bk_id)+1 As new_id FROM book WITH(ROWLOCK)
とかして次にすぐInsertすれば解決なのかな?
>13
たしかに・・・。
ASPはじめてへぼいBBSが作れたと思った次の仕事がこれで
ようするにおれじゃまだむり・・・。
上司(というか社長)も自分はできるっていってるけど
ロックもトランザクションもやってなかったから知らないと思う。
(それを言うと知ってるって言う)
Webのデザインの会社なんで他に知ってる人いない・・・
おれがちょっと掲示板ぐらいだったら・・・って言ったら
全部やらされてて辛いっス。
>14
なんかオートナンバーは遅くなるからいかん
っていわれた。
おれはよくわかんない。
なんかIDがダブってもいいように作れって言われてるんですけど
なんかその場しのぎな感じがして嫌です。
UniqなIDを確実に作る処理って絶対必要な気がして。
00178=13
NGNG×Call rs.Open("book", CON, 3, 2)
○Call rs.Open(sSQL, CON, 3, 2)
>>1
IDがダブったらシステム的に話になりません。
オートナンバーは書き込んでみないと何番になったか分からんから、
その値で他のテーブルも更新しようとすると、もう一度読み直さなきゃきゃならんので、
俺的には自分で発番するほうが好き。発番用の管理テーブルを作ったりする場合も有り。
素人でも作れてしまうのが、VBの良いところでもあり、悪いところでもあるかな。
将来、VBが分かるようになってきたからといって、勘違いして複雑なシステムを請け負わないように。
00189
NGNGSELECT MAX(bk_id) As new_id FROM book WITH(UPDLOCK)
...
INSERT INTO book SELECT ... でMAX(bk_id)+1を追加
COMMIT
*COMMITするまでBOOKはSELECT文でさえLOCKされます。
0019デフォルトの名無しさん
NGNGSQL Server だと、常套手段はこれ。
1 主キー値に IDENTITY 属性をつけて、SQL サーバ側で採番させる。
2 INSERT 直後に @@IDENTITY で番号を取得。
>>16
IDENTITY は、それほど遅くないですよ。ためしに IDENTITY 有り・無しで
テーブルを作って INSERT の速度を測ってみると良いです。
0020デフォルトの名無しさん
NGNG00218=13
NGNGSELECT @@IDENTITY AS 'Identity'
で取れるのか。
素朴な疑問、IDENTITYが桁あふれしたらどうなるの?
0022デフォルトの名無しさん
NGNG00231
NGNGなるほど。超納得。
>19
おお。その常套手段っての知りたかった。
超基本っぽいことだから普通はどうやるのかなって。
IDENTITY関連調べてみます。
でもどっちがいいのかな。
つーか両方知ってなきゃいけないのか。
それともういっこ微妙に関係ないんですけど
普通、エラーがおきたときの情報なんかはどうするんですか
それ用のテーブルに残すとしたらどんな情報を残しとくんすか、常識的には。
0024デフォルトの名無しさん
NGNG私はローカルなファイルに書き出してますね。エラー時には、そもそも DB への
接続が死んでる可能性があるから DB には書きません。
内容は
1 タイムスタンプ
2 エラーを起こしたファイルの名前と行 (Internal Server Error の場合には
ASPError あたりから拾える)
3 Query String を含んだ URL と POST データ
4 SQL 文を動的に作っている場合には動的に作っている SQL 文の全体、
ストアドプロシージャ呼び出しの場合には、ストアドプロシージャ名とパ
ラメタの値
あたりを列挙。後でユーザから報告が上がってきたときに、どこが原因なのか
突き止められる程度に情報を残しておけば良いです。
0025Error401
NGNGIDENTITYは、トランザクションをロールバックしたときに、元の値に
戻るのかな?
だとすれば、どちらも一緒。
違う場合(多分こっちだと思うけど)、
・連番の保証をするなら、SELECTでロックかけ、自前で番号を振る
・連番保証の必要が無い場合は、IDENTITYを使う
という使い分けをします。
>普通、エラーがおきたときの情報なんかはどうするんですか
トランザクションの内部で、自立したトランザクション(外側のトランザクション
に関係なく、コミット・ロールバックできるトランザクション)が使えない場合は、
テーブルにエラー情報を吐き出すことは出来ません。SQL Serverで使えるか
どうかは知りませんけど。
>それ用のテーブルに残すとしたらどんな情報を残しとくんすか、常識的には。
常識的には、自分が知りたいものを残しておきます、フツー(藁
0026デフォルトの名無しさん
NGNGに書いた後テーブルに書くという手段をとっている
のですが、こういう事をするのは少数派なのかな?
00272
NGNGCON.BeginTrans()
On Error Goto DBError
SQL = "SELECT MAX(bk_id) max_id FROM book"
SET RS = CON.Execute(SQL)
If RS.EOF Then
newbk_id = 1
Else
newbk_id = RS("max_id")+1
End If
rs.close
Conn.Execute "Insert into book (bk_id) values (' + newbk_id + ")"
CON.CommitTrans
Exit Sub
DBError:
CON.RollBackTrans
response.redirect "error.asp"
end if
0028デフォルトの名無しさん
NGNG出力位置が大きく下に出力するんですけど。
なにか心当たりあるひと教えてくれません
0029デフォルトの名無しさん
NGNGスバラシイ!
さすが、VB使い!
0030デフォルトの名無しさん
NGNGこれ以上、恥をさらさないほうがいいよ。馬路で。
0031デフォルトの名無しさん
NGNGいいかげん、ウザイんだよ。
0032デフォルトの名無しさん
NGNGASP の VBScript には On Error GoTo ないぞ(正確には On Error GoTo 0,
On Error Resume Next だけ使える)。
003327
NGNGそーか、ごめん。
IIS+ASPにはもう何年も触ってないのに適当なこと書いちゃった。
そうすると、この場合のエラー処理はどうするんだろう。On Error Resume Next
しておいて、ConnectionオブジェクトのErrorsプロパティをチェックすれば
できるのかな?
0034デフォルトの名無しさん
NGNGつーか、そんな枝葉じゃなくて、根本的なトコロが間違ってるのよ。
0035デフォルトの名無しさん
NGNGまじで、痛すぎるよ。
カキコ控えてROMに徹したほうが身のためだよ。
00361
NGNG先の処理をまっててくれる⇒ROCKにしたい所存。
↑こういう現状です。
>9
で言ってるようにWITH(UPDLOCK)ってのがつかえないんすが・・・
>Error401
調べ中に見つけたんすけどロールバックされたら@@IDENTITYは元に戻らないそうです。
0037デフォルトの名無しさん
NGNGそして、そのtableに
update dummy set dummy = max + 1 where dummy = max;
としてupdateを発行しないの?他のセッションが同時期におなじupdate文を
発行したなら、dummy = maxのrowは存在しなくなるから変更は行われない。
変更行がなかった場合にはもう一度maxの取得をして変更できるまで繰り返す。
update文の実行はアトミックであることが保証されてるからmax + 1もアトミックな
値が返るぞ。
0038デフォルトの名無しさん
NGNG人を批判する前に自分の考えを示しな。
27の方が多少なりともえらいぞ。
ちなみにおれはASP使いじゃないからしらん。
0039Error401
NGNGうーん、update dummy文が1文1トランザクションだとすると、連番保証が
なくなるので、IDENTITYを使うのと変わらないし、
更新対象のupdate文と同じトランザクションに入れるのなら、
select max(id) + 1と変わらない気がするんですけど・・・。
>>38
えーと、>>27のコードは、本質的に>>1となんら変わりがないので
批判されてるんじゃないかと思います。
解決法はすでに出尽くしてると思うし。
0040デフォルトの名無しさん
NGNGASPとかそうゆう問題じゃないんだよ。
それがわからないお前も逝ってよし。
さすが、Error401氏
004127
NGNG>>39
すいません。後で気が付いたんですが、その通りですね。
それで、昔同じようなことをしたのを思い出しました。そのときの解決法は
>>37のようにMAX値保存テーブルを作成し、ストアドプロシージャで
1. 現在のMAX値を更新用カーソルで取得する
2. インクリメントしたMAX値をそのカーソルを使用して更新する
を1トランザクションで実行し、成功したら更新したMAX値を返す、という方法を
取りました。
00421
NGNGありがとうございます。なんとなくわかってきたかも。
発番用のテーブルを用意するってのはそういうことだったんすね。13
そんで今わからないのがその重複しちゃ困るIDで同時に
もう1個のテーブルをINSERTまたはUPDATEしてるんですけど
「そのカーソルだと複数にまたがったトランザクションできません」
みたいなエラーがでます。
(ロックタイプ、カーソルは 3.3 です。)
0043便乗質問でスミマセン
NGNGある条件で、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ある条件で、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
NGNG0047
NGNG〜
UPDATE //ロック解除
だったような気がする。
0048
NGNG0049デフォルトの名無しさん
NGNG2 INSERT 直後に @@IDENTITY で番号を取得。
のコードの書き方教えて
WHERE ... AND (ROWNUM >10) AND (ROWNUM <16)
だったような気がする。
0051デフォルトの名無しさん
NGNGもうちょっとくわしく説明して下さい
なぜ、別に一個 1rowだけのMAXナンバーを格納したTableを作らんの?
そして、そのtableに
update dummy set dummy = max + 1 where dummy = max;
としてupdateを発行しないの?他のセッションが同時期におなじupdate文を
発行したなら、dummy = maxのrowは存在しなくなるから変更は行われない。
変更行がなかった場合にはもう一度maxの取得をして変更できるまで繰り返す。
update文の実行はアトミックであることが保証されてるからmax + 1もアトミックな
値が返るぞ。
005243
NGNGそれはつまり、マルチスレッドというもので解決できるのでしょうか?
ありがとうございます。後は自分で調べてみます。
0053デフォルトの名無しさん
NGNGしかし、落とし穴があって、システムが異常終了するとこの連番が狂うので、DBCCで修正してやらないといけない
0054デフォルトの名無しさん
NGNG他のセッションが同時期におなじupdate文を
発行したなら、dummy = maxのrowは存在しなくなるから変更は行われない
この理由がよくわからないのですが
0056仕様書無しさん
NGNGふたつのセッションで同じ値の max (仮に10とする) を取得してしまったとしても、
そのうちのひとつのセッションで、先に dummy = max + 1 ( dummy = 10 + 1 ) に
書き換えれば、dummy = 10 の行は存在しなくなるでしょ。
もうひとつのセッションで dummy = 10 の行への書き込みを試みても、そんな行は
もうないから、書き込みは行えないというわけ。
0057デフォルトの名無しさん
NGNG複数のクライアントからアクセスすると、「容量を超えていたため、
新規トランザクションを作成できません。」というエラーが返ってきます。
そこで、もしMSDEのトランザクション領域(デフォルト)のサイズをご存知の方が
いらっしゃいましたら、教えていただけないでしょうか?
よろしくお願いします。
0058縞栗鼠(シマリス)の親方
NGNG汚物入れを物色して女子生徒の使用済みタンポン・ナプキン等を
個人的に収集しているというのは事実。
中央高等学院では
生徒及びその保護者の個人情報を名簿図書館等に売却しています。
中央高等学院 http://chs-f.com/index.html 中央高等学院福岡校
http://www.chuo-school.ac/
0059名無しさん@Emacs
NGNGFAQなのレス。
(>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名無しさん@Emacs
NGNGあと、間違ってた...鬱だ...
最後は ROWNUM < 11 ですわな...
0061デフォルトの名無しさん
NGNGMAX+1に適当なダミーデータを放り込んでおいて、INSERTの変わりにUPDATE
すべきかと思われ。
SQL*Serverにあるのかどうか知らんが、SWQENCEつかうのが一番いいとおもわれ。
0062デフォルトの名無しさん
NGNG方法1.1〜3をBEGIN TRANSACTIONとCOMMITで囲む。(これにより排他がかかる)
方法2.ユニークインデックスにして、重複エラー時は適当な時間をおいてリトライさせる。
方法3.1〜2を3のトリガー処理に書きSQL分を一つにする。トリガー処理は一意であるのでOKになる。
■ このスレッドは過去ログ倉庫に格納されています