Wyłącz jawne zatwierdzenia w JDBC, wykryj je w SQL lub ustaw bazę danych w trybie tylko do odczytu

12

Tło : Pracuję na http://sqlfiddle.com (moja strona) i staram się zapobiec jednej możliwej nadużyciu. Mam nadzieję, że pytając o problem, który obecnie rozwiązuję, nie zwiększam nieumyślnie potencjalnego nadużycia, ale co możesz zrobić? Ufam wam, ludzie.

Chciałbym uniemożliwić użytkownikom wykonywanie wyraźnych wywołań „zatwierdzania” w ramach danego bloku transakcji. W kontekście SQL Fiddle blokiem transakcji jest kod wykonywany na panelu po prawej stronie. Zasadniczo zapętlam i wykonuję listę poleceń SQL w postaci jawnego tekstu i chcę mieć pewność, że wszystkie zmiany, które wprowadzą, zostaną wycofane na końcu partii. Zwykle ich zmiany są wycofywane, ale czasami w tekście jest wyraźne polecenie „zatwierdzenia”, więc moje wycofanie nie zadziała. To jawne zatwierdzenie jest bardzo prawdopodobne od użytkownika próbującego złamać schemat w SQL Fiddle, więc inne osoby pracujące nad nim zobaczą błędy.

Główny pożądany wynik : Jeśli to możliwe, chciałbym wyłączyć jawne zatwierdzenia na poziomie JDBC. To dlatego, że muszę obsługiwać wielu dostawców zaplecza bazy danych i oczywiście każdy ma swoje dziwactwa na niskim poziomie.

Opcja rezerwowa : jeśli nie jest możliwe skonfigurowanie JDBC do wyłączania jawnych zatwierdzeń, byłbym otwarty na rozwiązania do wykrywania jawnych zatwierdzeń podczas przetwarzania wsadu dla każdego z następujących backendów: SQL Server, Oracle, MySQL i PostgreSQL.

W przypadku programu SQL Server pomyślałem o tym rozwiązaniu: przeanalizuj plan zapytania XML dla instrukcji, zanim ją wykonam, i sprawdź, czy istnieje pozycja pasująca do tej XPath:

//*[@StatementType="COMMIT TRANSACTION"]

Myślę, że to działałoby całkiem dobrze dla SQL Server. Jednak to podejście nie działa w przypadku innych typów DB. Dane wyjściowe planu wykonania XML Oracle dla jawnych zatwierdzeń nie odnoszą się do faktu, że uruchamiasz instrukcję commit (a raczej po prostu powtarza dane wyjściowe planu wykonania z zapytań, które popełnia). PostgreSQL i MySQL nie zapewniają żadnych danych wyjściowych planu wykonania (XML lub w inny sposób) dla jawnych zatwierdzeń.

To pozostawia mi sprawdzenie faktycznej instrukcji pod kątem słowa „commit”. To by działało, z tym wyjątkiem, że mogą istnieć wszelkiego rodzaju warianty:

declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);

Powyższy przykład jest przykładem SQL Servera (który mógłbym obejść), ale przypuszczam, że podobne rzeczy byłyby możliwe w przypadku Oracle, MySQL i PostgreSQL. Czy mylę się przy tym założeniu? Może nie pozwolą na „dynamiczne” instrukcje zatwierdzania? Zachęcamy do skorzystania z SQL Fiddle (najlepiej nie z przykładowego schematu lub innej osoby, nad którą prawdopodobnie będzie pracował), aby sprawdzić, czy można zrobić coś podobnego w Oracle, MySQL i PostgreSQL. Jeśli nie, być może proste wykrywanie ciągu może być dla nich skuteczne.

Jeszcze jedna możliwość

Inna opcja przyszła mi do głowy - jeśli znasz sposób na ustawienie dowolnej z tych baz danych w trybie tylko do odczytu, na przykład w tym trybie nic nie może zostać popełnione, to też może działać. Musiałbym nadal zezwalać na uruchamianie transakcji i uruchamianie w nich kodu, tak długo, jak nic nie może zostać zatwierdzone w tym trybie. Czy to jest możliwe?

Aktualizacja

Czego się ostatnio nauczyłem - tak naprawdę nie jest to problem z PostgreSQL. Najwyraźniej zatwierdzenia wydane w ramach bloku transakcji nie będą miały zastosowania, jeśli ten sam blok ostatecznie zostanie wycofany (w Postgres). Więc Brawo dla Postgres!

Dzięki linkowi Phila do postu SO, myślę, że mogę użyć hakowania ODCZYTOWO POCZĄTKOWO ODRÓŻNIONEGO dla Oracle, aby osiągnąć to, czego szukam (błąd zostanie zgłoszony, jeśli zostanie wydane zatwierdzenie, ale mogę to obejść). To powinno zwrócić się do Oracle. (Przez chwilę myślałem, że transakcje zagnieżdżone mogą tu działać, ale nie wygląda na to, że Oracle obsługuje transakcje zagnieżdżone? W każdym razie nie mogłem znaleźć niczego, co działałoby w ten sposób).

Nie mam jeszcze rozwiązania dla MySQL. Próbowałem użyć transakcji zagnieżdżonych, ale wydaje się, że to nie działa. Poważnie myślę o bardziej drastycznych podejściach do MySQL, takich jak albo nie zezwalanie na nic oprócz SELECT po prawej stronie lub upuszczanie / odtwarzanie DB po każdym zapytaniu. Żaden z nich nie brzmi dobrze.

Rozkład

Wdrożyłem więc opisane rozwiązania dla SQL Server i Oracle, a jak już wspomniałem, nie jest to tak naprawdę problem dla PostgreSQL. W przypadku MySQL podjąłem nieco niefortunny krok polegający na ograniczeniu panelu zapytań tylko do wybierania instrukcji. DDL i DML dla MySQL należy po prostu wprowadzić w panelu schematu (po lewej stronie). Mam nadzieję, że nie złamie to zbyt wielu starych skrzypiec, ale myślę, że to po prostu to, co należy zrobić, aby zapewnić spójność danych. Dzięki!

Jake Feasel
źródło
Warto wspomnieć - przeprowadziłem również wiele badań dotyczących wyzwalaczy „poprzedzających zatwierdzenie”. Wygląda na to, że nie istnieją, więc niestety nie jest to również opcja.
Jake Feasel
2
Dla Oracle wydaje się to dobrym sprytnym sposobem na złapanie COMMIT-ów: stackoverflow.com/a/6463800/790702 Nie wspomina o tym, że powinieneś być w stanie wykryć naruszenie ograniczenia również w swoim kodzie, aby zatrzymać drugą sytuację występujący.
Philᵀᴹ
@Pilko jedynym problemem jest to, że nie mam (i tak naprawdę nie chcę) kontroli nad definicją każdej z tabel (są one zdefiniowane na lewym panelu). Aby klauzula DEFERRABLE INITIALLY DEFERRED nie istniała (chyba że istnieje jakiś sposób, aby zrobić to automatycznie dla wszystkich tabel - powiedzmy za pomocą wyzwalacza systemowego, który reaguje na tworzenie instrukcji tabeli? Ugh)
Jake Feasel
1
@NickChammas Muszę wyłączyć zatwierdzenia, aby utrzymać schemat (zdefiniowany przez lewy panel boczny) w ustalonym stanie. Może istnieć dowolna liczba osób piszących zapytania dotyczące tego samego schematu, próbujących rozwiązać ten sam problem. Aby nie kolidowały ze sobą, muszę się upewnić, że struktura i dane się nie zmieniają. Odbywa się to poprzez wycofane transakcje, ale nie dzieje się tak, jeśli zostanie zatwierdzony kod po prawej stronie.
Jake Feasel
2
@RickJames DDL tworzy niejawne zatwierdzenia w MySQL i Oracle, ale nie w PostgreSQL ani SQL Server. Mechanizmy, które wdrożyłem w następstwie tego posta, radzą sobie z tym problemem. Jeśli chodzi o wprowadzanie arbitralnego SQL - o to chodzi!
Jake Feasel,

Odpowiedzi:

3

Dla Oracle wydaje się to dobrym sprytnym sposobem na złapanie COMMIT-ów:

/programming//a/6463800/790702

To, czego nie wspomina, to to, że powinieneś być w stanie wychwycić naruszenie ograniczenia również w swoim kodzie, aby zatrzymać występowanie drugiej sytuacji.

Philᵀᴹ
źródło
Świetnie, jeszcze raz dziękuję Phil. Udało mi się dobrze wykorzystać tę technikę dla Oracle. To sprawia, że ​​życzę innym odroczonym ograniczeniom obsługiwanych baz danych.
Jake Feasel
Bez obaw.
Wejdź