3

次のようなテーブルスキームがあります。

CREATE TABLE IF NOT EXISTS `offers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `campaign_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `price` double NOT NULL,
  `ip` varchar(15) NOT NULL,
  `cdate` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `campaign_id` (`campaign_id`,`price`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin5 AUTO_INCREMENT=190514 ;

ユーザーによる新しいオファーごとに、最後の注文が同じユーザーによって与えられたかどうかを確認します。

"select user_id from offers where campaign_id='".$campaign['id']."' order by id desc limit 1"

user_id が同じである場合、ユーザーを偶発的なダブルクリックから保護するために、新しいオファーを防止します。

オファーに問題がない場合は、オファーを次のように挿入します。

"insert into offers(campaign_id,user_id,price,ip,cdate) values (".$campaign['id'].",".$user['id'].",'".$price."','".$_SERVER['REMOTE_ADDR']."',".time().")"

しかし、問題は、選択が約 1 秒後に最後に挿入された行のみを返すことです。つまり、ユーザーがボタンをクリックする速度が速すぎると、複数のオファーを挿入できます。

データベース サーバーとして 5.5.30-30.2-log Percona サーバーを使用します。以下は、my.cnf ファイルです。

[mysqld]
datadir                         = /var/lib/mysql
tmpdir                          = /var/lib/mysqltmp
socket                          = /var/lib/mysql/mysql.sock
skip-external-locking           = 1
skip-name-resolve
open-files-limit                = 40000
max_heap_table_size             = 64M
tmp_table_size                  = 64M
log-error                       = /var/log/mysqld.log
thread-cache-size               = 50
table-cache                     = 4096
table-open-cache                = 4096
table-definition-cache          = 512
query-cache-size                = 0
query-cache-limit               = 16M
query-cache-type                = 0
sort-buffer-size                = 1M
read-buffer-size                = 1M
read-rnd-buffer-size            = 8M
join-buffer-size                = 1M
tmp-table-size                  = 64M
max-heap-table-size             = 64M
back-log                        = 100
max-connections                 = 10000
max-connect-errors              = 10000
max-allowed-packet              = 256M
interactive-timeout             = 360
wait-timeout                    = 360
innodb                          = FORCE
key-buffer-size                 = 32M
myisam-sort-buffer-size         = 4M
innodb-buffer-pool-size         = 60G
innodb-log-file-size            = 256M
innodb_log_files_in_group       = 2
innodb-log-buffer-size          = 4M
innodb-file-per-table          = 1
innodb-thread-concurrency       = 8
innodb-flush-log-at-trx-commit  =2
server-id                       = 1
slow-query-log                  = 1
slow-query-log-file             = /var/lib/mysqllogs/slow-log
4

4 に答える 4

1

たとえば、更新/挿入イベントでSQLトリガーを使用して、次のことを確認しようとしましたか?

SELECT count(*) FROM `offers` 
WHERE campaign_id = [Your_value] AND user_id = [Your_value];

は 0 に等しく、それに従って行動します。(既に存在する場合は、変更を行わないでください [...])

編集:ちなみに、MySQLデータベースの誤った使用ではなく、Ajax / Php /使用しているものは何でも問題のようです。ユーザーが短い間隔で多くのリクエストを送信しないようにする必要があります。

于 2013-05-03T14:14:15.637 に答える
0

次のように、挿入の前に同じ行を選択する複数の接続が原因で問題が発生したと思います。

PHP 接続 1: 最後のオファー user_id を選択します

PHP 接続 2: 最後のオファー user_id を選択します (同じものを指定してください)

PHP 接続 1: オファーを挿入する

PHP 接続 2: オファーを挿入する

次のように、選択する前にテーブルをロックし、挿入後にロックを解除することで問題を解決しました。

ロックテーブルは書き込みを提供します

最後のオファーの user_id を選択します

現在のユーザー挿入オファーと異なる場合

テーブルオファーのロックを解除

于 2013-05-03T19:48:50.727 に答える
0

挿入をトランザクションに明示的にラップしようとしましたか? 次のようなことをします:

START TRANSACTION
INSERT ...
COMMIT
SELECT ...

これにより、SELECT が最後に挿入されたデータを返すことが保証されます。

InnoDB 分離レベルの詳細: [1]および[2]

于 2013-05-03T15:00:40.937 に答える
0

MySQL クエリ キャッシング。

MySQL は最初のクリックをチェックして空の結果を返します。次にレコードを挿入し、その後のクリックごとに MySQL は空の結果のキャッシュされた値を返し、別の挿入を許可します。

私が取り組んでいたサイトで、リクエストが非常に接近していて、同様のことが起こりました。

これを最初に実行する必要がありました

SET SESSION query_cache_type=0;
于 2013-05-03T13:41:19.510 に答える