Как заблокировать чтение / запись в таблицы MySQL, чтобы я мог выбирать и затем вставлять без других программ, читающих / записывающих в базу данных?

Я запускаю несколько экземпляров веб-сканера параллельно.

Каждый сканер выбирает домен из таблицы, вставляет этот URL и время начала в таблицу журнала, а затем начинает сканирование домена.

Другие параллельные сканеры проверяют таблицу журналов, чтобы увидеть, какие домены уже сканируются, прежде чем выбирать свой собственный домен для сканирования.

Мне нужно запретить другим поисковым роботам выбирать домен, который был только что выбран другим поисковым роботом, но не еще есть запись в журнале. Я могу предположить, как это сделать, - заблокировать базу данных от всех других операций чтения / записи, пока один искатель выбирает домен и вставляет строку в таблицу журнала (два запроса).

Как, черт возьми, это сделать? Боюсь, это очень сложно и зависит от многих других вещей. Помогите мне начать работу.


Этот код кажется хорошим решением (однако см. Ошибку ниже):

INSERT INTO crawlLog (companyId, timeStartCrawling)
VALUES
(
    (
        SELECT companies.id FROM companies
        LEFT OUTER JOIN crawlLog
        ON companies.id = crawlLog.companyId
        WHERE crawlLog.companyId IS NULL
        LIMIT 1
    ),
    now()
)

, но я продолжаю получать следующую ошибку mysql:

You can't specify target table 'crawlLog' for update in FROM clause

Есть ли способ сделать то же самое без Эта проблема? Я пробовал несколько разных способов. Включая это:

INSERT INTO crawlLog (companyId, timeStartCrawling)
VALUES
(
    (
        SELECT id
        FROM companies
        WHERE id NOT IN (SELECT companyId FROM crawlLog) LIMIT 1
    ),
    now()
)
27
задан OMG Ponies 13 July 2011 в 03:17
поделиться

2 ответа

Вы, вероятно, не хотите блокировать стол. Если вы сделаете это, вам придется беспокоиться о перехвате ошибок, когда другие сканеры пытаются записать в базу данных - о чем вы подумали, когда сказали «... ужасно сложный и основанный на многих других вещах».

Вместо этого вам, вероятно, следует заключить группу запросов в транзакцию MySQL (см. http://dev.mysql.com/doc/refman/5.0/en/commit.html ) следующим образом:

START TRANSACTION;
SELECT @URL:=url FROM tablewiththeurls WHERE uncrawled=1 ORDER BY somecriterion LIMIT 1;
INSERT INTO loggingtable SET url=@URL;
COMMIT;

Или что-то близкое к этому.

[править] Я только что понял - вы, вероятно, можете сделать все, что вам нужно, в одном запросе, и вам даже не придется беспокоиться о транзакциях. Примерно так:

INSERT INTO loggingtable (url) SELECT url FROM tablewithurls u LEFT JOIN loggingtable l ON l.url=t.url WHERE {some criterion used to pick the url to work on} AND l.url IS NULL.
4
ответ дан 28 November 2019 в 04:50
поделиться

Ну, настольные блокировки - один из способов справиться с этим; но это делает параллельные запросы невозможными. Если таблица InnoDB, вы можете вместо этого принудительно заблокировать строку, используя SELECT ... FOR UPDATE в транзакции.

BEGIN;

SELECT ... FROM your_table WHERE domainname = ... FOR UPDATE

# do whatever you have to do

COMMIT;

Обратите внимание, что для этого вам понадобится индекс на domainname (или любой другой столбец, который вы используете в предложении WHERE), но в целом это имеет смысл, и я предполагаю, что у вас будет это в любом случае.

3
ответ дан 28 November 2019 в 04:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: