Я запускаю программу, которая составляет таблицу и затем вставляет некоторые данные.
Это - единственная программа, это получает доступ к базе данных.
Я получаю РТЫ 08177 случайным образом.
Фактический код несколько сложен, но я записал простую программу, которая воспроизводит это поведение.
using System;
using System.Data;
using Oracle.DataAccess.Client;
namespace orabug
{
class Program
{
private const string ConnectionString = ""; // Valid connection string here
// Recreates the table
private static void Recreate()
{
using (var connection = new OracleConnection(ConnectionString)) {
connection.Open();
using (var command = connection.CreateCommand()) {
command.CommandText = @"
declare
table_count binary_integer;
begin
select count(*) into table_count from sys.user_tables where table_name = 'TESTTABLE';
if table_count > 0 then
execute immediate 'drop table TestTable purge';
end if;
execute immediate 'create table TestTable(id nvarchar2(32) primary key)';
end;";
command.ExecuteNonQuery();
}
connection.Close();
}
}
// Opens session sessionCount times, inserts insertCount rows in each session.
private static void Insert(int sessionCount, int insertCount)
{
for (int sessionNumber = 0; sessionNumber < sessionCount; sessionNumber++)
using (var connection = new OracleConnection(ConnectionString)) {
connection.Open();
using (var transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
for (int insertNumber = 0; insertNumber < insertCount; insertNumber++)
using (var command = connection.CreateCommand()) {
command.BindByName = true;
command.CommandText = "insert into TestTable (id) values(:id)";
var id = Guid.NewGuid().ToString("N");
var parameter = new OracleParameter("id", OracleDbType.NVarchar2) {Value = id};
command.Parameters.Add(parameter);
command.Transaction = transaction;
command.ExecuteNonQuery();
}
transaction.Commit();
}
connection.Close();
}
}
static void Main(string[] args)
{
int iteration = 0;
while (true) {
Console.WriteLine("Running iteration: {0}", iteration);
try {
Recreate();
Insert(10, 100);
Console.WriteLine("No error");
}
catch (Exception exception) {
Console.WriteLine(exception.Message);
}
iteration++;
}
}
}
}
Этот код выполняет бесконечный цикл.
На каждом повторении это выполняет следующие действия 10 раз:
Открытое заседание
Вставьте 100 строк со случайными данными
Закройте сеанс
Отображает сообщение, говоря, что никакая ошибка не произошла
Если ошибка происходит, исключение поймано, и его сообщение печатается, и затем следующее повторение выполняется.
Вот демонстрационный вывод. Поскольку Вы видите, что РТЫ 08177 чередуются с успешными взаимодействиями случайным образом.
Running iteration: 1
No error
Running iteration: 2
ORA-08177: can't serialize access for this transaction
Running iteration: 3
ORA-08177: can't serialize access for this transaction
Running iteration: 4
ORA-08177: can't serialize access for this transaction
Running iteration: 5
ORA-08177: can't serialize access for this transaction
Running iteration: 6
ORA-08177: can't serialize access for this transaction
Running iteration: 7
No error
Running iteration: 8
No error
Running iteration: 9
ORA-08177: can't serialize access for this transaction
Running iteration: 10
ORA-08177: can't serialize access for this transaction
Running iteration: 11
ORA-08177: can't serialize access for this transaction
Running iteration: 12
ORA-08177: can't serialize access for this transaction
Running iteration: 13
ORA-08177: can't serialize access for this transaction
Running iteration: 14
ORA-08177: can't serialize access for this transaction
Running iteration: 15
ORA-08177: can't serialize access for this transaction
Running iteration: 16
ORA-08177: can't serialize access for this transaction
Running iteration: 17
No error
Running iteration: 18
No error
Running iteration: 19
ORA-08177: can't serialize access for this transaction
Running iteration: 20
No error
Я выполняю Oracle 11.1.0.6.0 и использую ODP.NET 2.111.6.20.
Изменение уровня изоляции к ReadCommited
решает проблему, но я действительно хочу выполнить это в Serializable
уровень.
Похож я не являюсь одним с этой проблемой, но ответ не был дан, таким образом, я спрашиваю снова.
Что я делаю неправильно и как я мог зафиксировать это?
редактирование APC
Для предотвращения кого-либо еще лающего неправильное дерево отправленный пример кода является просто генератором РТОВ 8 177 ошибок. По-видимому, фактический код отличается; а именно, отбрасывание и воссоздание таблиц являются отвлекающим маневром.
В комментариях пользователь Гэри разместил ссылку на ветку, объясняющую это странное поведение. Вскоре, иногда во время реструктуризации индекса данные отмены становятся недоступны. Любая транзакция, которая выполняется на уровне сериализуемой изоляции и запрашивает данные, так или иначе связанные с этим индексом, получат ORA-08177. Это наполовину ошибка, наполовину функция Oracle. ROWDEPENDENCIES снижает вероятность получения этой ошибки. Для моего приложения я просто переключился на уровень ReadCommited для больших загрузок данных. {{1 }} Похоже, что нет другого способа полностью избавиться от этой проблемы.
Спасибо, Гэри, я поддержал ваш ответ на другой вопрос.
Полная перезапись неправильное дерево в первый раз).
Уровень изоляции SERIALIZABLE захватывает слот в Списке заинтересованных транзакций. Если Oracle не может получить слот, он выбрасывает ORA-8177. Количество доступных слотов ITL контролируется INITRANS и MAXTRANS. Согласно документации :
Чтобы использовать сериализуемый режим, INITRANS должен быть установлен как минимум на 3.
Это должно быть установлено как для таблицы, так и для ее индексов. Итак, каковы ваши настройки INITRANS? Конечно, в вашем примере кода используется значение по умолчанию (1 для таблиц, 2 для индексов).