TL; версия DR:
У меня есть две транзакции в хранимой процедуре MySQL. Второй зависит от данных, вставленных первым. Я использую SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
и COMMIT AND CHAIN
в конце первой транзакции, но вторая транзакция, кажется, не видит данные первой.
Если после этого я выполню тот же запрос, что и во второй транзакции, он выполнит то, что ожидал. Поэтому мне нужно, чтобы вторая транзакция действительно ожидала завершения первой.
Подробности:
У меня есть хранимая процедура в MySQL 5.6 по существу, создается запись в таблице, в которой перечислены некоторые элементы, а затем создается копия данных, относящихся к родительскому элементу. Затем эти данные объединяются в другую таблицу, которая не изменяется.
В этом примере:
r_subject -1: N-> put_test_join -1: 1-> put_test_data
put_test_bundles также имеет отношение к put_test_join, по существу, чтобы идентифицировать имя тестового пакета для заданных данных. Меня не особенно беспокоит структура базы данных, а скорее проблема, возникающая у меня с процедурой:
create procedure create_branch(IN _branch_name varchar(255), IN _project varchar(255),
IN _subver varchar(255), IN _revision int(10),
IN _parent varchar(255), IN _owner varchar(255))
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE parent_id INT UNSIGNED;
DECLARE new_tbid INT UNSIGNED;
DECLARE _rid INT UNSIGNED;
DECLARE _pgid INT UNSIGNED;
DECLARE _pdid INT UNSIGNED;
DECLARE _dupe_id INT UNSIGNED;
DECLARE _rfu_id INT UNSIGNED;
DECLARE ptj_cursor CURSOR FOR SELECT rid,pgid,pdid,dupe_id,rfu_id FROM put_test_join WHERE tbid = parent_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
DECLARE exit handler for SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,
@errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
SET @full_error = CONCAT('ERROR ', @errno, ' (', @sqlstate, '): ', @text);
SELECT @full_error;
END;
IF (SELECT COALESCE(id) FROM put_test_bundles WHERE put_test_bundles.name = _branch_name AND project = _project AND subver = _subver LIMIT 1) IS NOT NULL THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'This branch already exists';
END IF; # Check for dupes
SELECT id INTO parent_id FROM put_test_bundles WHERE name = _parent AND project = _project AND subver = _subver;
IF (parent_id IS NULL) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Parent not found';
END IF;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
OPEN ptj_cursor;
START TRANSACTION;
INSERT INTO put_test_bundles (name, project, subver, revision, parent, owner, istest, locked) VALUES (_branch_name, _project, _subver, _revision, parent_id, _owner, 0, 0);
SET new_tbid = LAST_INSERT_ID();
ptd_loop: LOOP
IF done THEN
LEAVE ptd_loop;
END IF;
FETCH NEXT FROM ptj_cursor INTO _rid, _pgid, _pdid, _dupe_id, _rfu_id;
INSERT INTO put_test_data (location_override, bit_override, test_name, pe_description, trimtest, tr_skip, td_skip, tbd, test_in, test_out, test_out_p2, test_out_p3, test_out_p4, mask_blow, high, low, step, default_setting, operating_value, mask_address, mask_row, iteration, username, updatedBy) SELECT location_override, bit_override, test_name, pe_description, trimtest, tr_skip, td_skip, tbd, test_in, test_out, test_out_p2, test_out_p3, test_out_p4, mask_blow, high, low, step, default_setting, operating_value, mask_address, mask_row, iteration, username, updatedBy FROM put_test_data WHERE id = _pdid;
INSERT INTO put_test_join (rid, tbid, pgid, pdid, dupe_id, rfu_id) VALUES (_rid, new_tbid, _pgid, LAST_INSERT_ID(), _dupe_id, _rfu_id);
END LOOP;
COMMIT AND CHAIN;
CLOSE ptj_cursor;
UPDATE put_test_data JOIN
(SELECT parent.id as parent_id,dupe.id as dupe_id FROM
(SELECT t.name,r.project,r.location,r.location_bit,d.id
FROM put_test_data d
JOIN put_test_join ptj on d.id = ptj.pdid
JOIN r_subject r ON ptj.rid = r.rid
JOIN put_test_bundles t ON ptj.tbid = t.id
WHERE t.name = _branch_name and r.project = _project FOR UPDATE) parent
JOIN
(SELECT t.name,p.project,p.location,p.location_bit,p.functionality,d.id,d.dupe_parent,d.dupe_diverged
FROM put_test_data d
JOIN put_test_join ptj on d.id = ptj.pdid
JOIN duplicates p ON ptj.dupe_id = p.rid
JOIN put_test_bundles t ON ptj.tbid = t.id
WHERE t.name = _branch_name and p.project = _project) dupe
ON parent.name = dupe.name
AND parent.project = dupe.project
AND parent.location = dupe.location
AND parent.location_bit = dupe.location_bit
WHERE parent.project = _project
AND parent.name = _branch_name) s ON put_test_data.id = s.dupe_id
SET put_test_data.dupe_parent = s.parent_id WHERE put_test_data.dupe_parent IS NULL AND s.parent_id IS NOT NULL;
COMMIT;
END;
По сути, это создает запись в put_test_bundles, а затем копирует все связанные родительские данные. и связывает их с новым тестовым пакетом и существующим r_subject.
Эта транзакция работает просто отлично, но после того, как она завершена, мне нужно просмотреть данные для идентификаторов данных, которые имеют дублирующуюся функциональность и "ссылку "их вместе. Я думаю, что это не удается, потому что вторая транзакция не может видеть данные первой транзакции. Я использую SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
и COMMIT AND CHAIN
в конце первой транзакции, но вторая транзакция не работает. Если я выполняю точно такой же запрос, как во второй транзакции, он выполняет то, что я ожидаю. Поэтому мне нужно, чтобы вторая транзакция действительно ожидала завершения первой.
Обновление: Я вызываю эту хранимую процедуру из парусов. js application. Даже когда я инкапсулировал второй запрос в другую хранимую процедуру и назвал их так:
let result = await sails.sendNativeQuery('CALL create_branch($1, $2, $3, $4, $5, $6);', [branch, project, subver, 0, parent, user]);
let linkCount = await sails.sendNativeQuery('CALL link_dupes($1, $2);', [project, branch]);
Вторая процедура все еще не видит данные из первой. Как я могу гарантировать, что первая процедура полностью зафиксирована и данные доступны для чтения перед выполнением второго запроса?