[MSSQL .NET] Как заблокировать БД?
транзакции - это типа не тру уже?
Не думаю, что кому-то нужно запускать сразу два менеджера пакетов в режиме установки/удаления. Тем более, что виндовый MSI этого не позволяет.
С ними есть проблемы. Если ты готов их разрешить - вперёд. Мне пока влом гуглить по этоу поводу.От имени всех админов, которые далее будут поддерживать БД, к которой ты пишешь некий интерфейс, предлагаю удалить все свои исходники и никогда больше не программировать.
Я и есть этот админ, нечего писать от моего имени, лол.
С ними есть проблемы.Может, ты и будешь узнавать, как они решаются, вместо поиска "как сделать транзакции без транзакций"?
Впрочем, разумеется, я знаю в чём проблема с транзакциями.
Я навскидку вижу только два механизма использования транзакций в менеджере пакетов и оба не годятся, имхо.
Вариант первый:
открываем транзакцию
читаем список пакетов
строим последовательность установки
ставим пакеты
завершаем транзакцию
Если первый пакет поставится, а второй нет - в БД не запишется информация об установке первого пакета.
Второй вариант:
читаем список для установки
ставим каждый пакет в отдельной транзакции
Проблема в том, что кто-то может поменять БД в промежутке между транзакциями, чего делать нельзя.
открываем транзакцию...
читаем список пакетов
строим последовательность установки
ставим первый из последовательности пакет
завершаем транзакцию
Долго
Базируются на optimistic concurrency.
Проблема в том, что я пока не знаю точно как именно они себя ведут.
Давно пора купить книгу...
что, мне правда надо было написать, что результаты первого шага надо кешировать и сравнивать первичные данные для определения необходимости выполнения 2го шага?
Совпадения входных данных (списка пакетов для установки) недостаточно для определения необходимости выполнения второго шага. В этом-то и заключается проблема.
Очевидно, список пакетов всегда тот же
Значит схема БД по-просту построена некорректно, раз этап сбора необходимых для анализа данных (без непосредственного их анализа!) занимает больше времени, чем установка одного "пакета".
Чтобы поставить пакет из одной exe-шки с 2 зависимостями достаточно проверить их наличие и скопировать эту exe-шку.
Чтобы построить дерево зависимостей для того же пакета, содержащее сотню-две других пакетов, требуется время. Ситуация, имхо, достаточно типичная (особенно если иметь дело с патчами).
Размещать ориентированный граф зависимостей в БД в виде матрицы достижимости слишком накладно с точки зрения занимаемого места (кроме того непонятно, как вписать в неё зависимости типа "хотябы одно из а, б, в").
"хотябы одно из а, б, в"meta-пакеты для чего по-твоему придуманы?
Однако это не решает проблемы представления их в БД.
Давно пора купить книгу...Мозги бы прикупил сначала
Прошу прощения за банальность
- я никого не просил предлагать другую схему БД или рассказывать о метапакетах (которые уже реализованы)
- меня устраивает текущий вариант, который строит один раз последовательность установки за O(размер дерева зависимостей) безо всяких накладныъх расходов на размер БД, и устанавливает каждый пакет без новых запросов. В нём нужно только запретить изменение БД из других соединений, о чём я и спросил
- я не претендую на то, что могу сразу написать идеальный код, который никогда не придётся изменять
безо всяких накладныъх расходов на размер БД,А они так и так появятся
Как "так"? Сейчас в БД хранится список версий в одной таблице, для каждой версии список имён пакетов, которые ей нужны в другой таблице. Более короткую запись придумать нельзя.
Вопрос был как залочить все изменения БД на время работы программы. А не как сделать транзакции.ты не должен этого хотеть (с)
почему, интересно, разработчики apt не сделали по-другому?
почему, интересно, разработчики apt не сделали по-другому?потому что разработчики apt не используют MSSQL?
Кстати о транзакциях. В данном случае они не решают всех проблем.
Требуется на время работы программы заблокировать возможность изменения БД (пишется менеджер пакетов)?хочешь сделать юзерскую блокировку, так сделай, а не тупи.
для этого транзакции и предусмотрены, чтобы можно было сделать произвольное атомарное поведение.
псевдокод
begin transaction
var locked = select locked from my_install_locks
if (locked)
throw new Exception("Установка невозможна, параллельно уже выполняется другая установка");
insert my_install_locks (locked) values(true)
bla-bla
устанавливаем пакеты
bla-bla
delete my_install_locks
commit
end transaction
Точно! Спасибо!
вот здесь, например, надо делать двойную проверку(до наложения лока и после т.к. есть вероятность, что одновременно может успеть начать выполняться несколько транзакций
var locked = select locked from my_install_locks
if (locked)
throw new Exception("Установка невозможна, параллельно уже выполняется другая установка");
insert my_install_locks (locked) values(true)
begin transaction
var locked = select locked from my_install_locks
if (locked)
throw new Exception("Установка невозможна, параллельно уже выполняется другая установка");
insert my_install_locks (locked) values(true)
bla-bla
устанавливаем пакеты
bla-bla
delete my_install_locks
commit
end transaction
уровень изодяции транзакции Serializable? если да, то код странный. Вот эти строчки
var locked = select locked from my_install_locks
if (locked)
throw new Exception("Установка невозможна, параллельно уже выполняется другая установка");
insert my_install_locks (locked) values(true)
delete my_install_locks
можно спокойно удалить, и все будет работать абсолютно так же! (разве что вероятность дедлоков уменьшится)
Наверное имелось ввиду — разнести выставление лока и длинную операцию по разным транзакциям?
надо делать двойную проверку(до наложения лока и послезачем двойная проверка, если мы в транзакции?
Можно еще Single user выставить на время работы - но это совсем жестко наверное
можно спокойно удалить, и все будет работать абсолютно так же! (разве что вероятность дедлоков уменьшится)поведение разное
в одном случае вторая инсталяция прерывается с ошибкой, во втором случае - она повисает на локах на неопределенное время
соответственно на это будет накладываться на то, что serializable транзакции дорогие, и что надо быть аккуратным с использованием всех таблиц из под такой транзакции - даже вспомогательных
например, мы в инсталяшку запихали чисто в трасировочных целях вот такое сообщение:
Trace.Write(select count(*) from user_objects);
но в итоге такая безобидная строчка - запрещает изменение user_objects на все время выполнения инсталяции с использованием serializable транзакций
ps
т.е. решение с serializable - имеет право на жизнь, но это разные решения: одно с явной проверкой, другое - с неявной.
а то же ли самое:begin transaction
var locked = select locked from my_install_locks
if (locked)
throw new Exception("Установка невозможна, параллельно уже выполняется другая установка");
insert my_install_locks (locked) values(true)
bla-bla
устанавливаем пакеты
bla-bla
delete my_install_locks
commit
end transaction
begin transaction 'some_unique_name'Я же правильно понимаю, что в системе не м.б. 2х транзакций одноимённых?
--doit
commit transaction 'some_unique_name'
end transaction 'some_unique_name'
Я же правильно понимаю, что в системе не м.б. 2х транзакций одноимённых?хз, с именнованными транзакциями не сталкивался.
и с ходу по msdn-у не понял, может быть две транзакции с одним именем, или нет...
Я же правильно понимаю, что в системе не м.б. 2х транзакций одноимённых?но в целом я сомневаюсь, что, например, у разных пользователей транзакции не могут иметь одно и тоже имя - т.к. если такое есть, то имея минимальные права можно легко положить базу целиком.
да и в разных сессиях - имена скорее всего тоже можно делать одиннаковыми - иначе получается, что если один тот же код пускается два раза, то генерит уникальные имена транзакции... такой генерации не припоминаю чтобы встречалось.
имея минимальные права можно легко положить базу целикомтогда в эти минимальные права должна входить возможность создавать порядка 2^(64*8) транзакций
тогда в эти минимальные права должна входить возможность создавать порядка 2^(64*8) транзакцийлибо поставить такую же систему себе на комп и посмотреть как называются транзакции.
т.к. какой у тебя уровень изоляции в первоначальном посте?
и что надо быть аккуратнымс остальными уровнями изоляции надо быть еще внимательнее
но в итоге такая безобидная строчка - запрещает изменение user_objects на все время выполнения инсталяции с использованием serializable транзакций
и что? вполне себе безобидная ошибка, по крайней мере, не прошли неверные операции. Меня, например, больше напрягает, когда из-за отсутствия транзакций (или низком уровне изолиции) итоговая сумма по заказу выводится на экран не верно.
и что? вполне себе безобидная ошибка, по крайней мере, не прошли неверные операции.не хрена себе безобидная, если обновление длится, например, десятки минут, то на эти десятки минут подвисают все пользователи активно меняющие эти самые user_objects.
и посмотреть как называются транзакцииимена могут генерироваться на лету
а доступ к таблице, в которой их хранить, необязательно давать всем подряд
имена могут генерироваться на летуможно конечно, но как уже говорил выше, с ходу такое по примерам и исходникам не припоминаю
не хрена себе безобидная, если обновление длится, например, десятки минут, то на эти десятки минут подвисают все пользователи активно меняющие эти самые user_objects.Эта ошибка относительно легко вылавливается на этапе тестирования. Если нормального тестирования не было, то все равно лучше уйти в продакшен с такой багой, чем с багой, когда время от времени буду проходить неверные операции (такие ошибки легко допустить при низком уровне изоляции).
не даром же у TransactionScope по умолчанию стоит уровень изоляции Serializable
Оставить комментарий
agaaaa
Требуется на время работы программы заблокировать возможность изменения БД (пишется менеджер пакетов)?