JDBC에서 명시 적 커밋을 비활성화하거나 SQL에서 감지하거나 데이터베이스를 읽기 전용 상태로 설정


12

배경 : http://sqlfiddle.com (내 사이트)에서 작업 중이며 가능한 한 악용 사례를 방지하려고합니다. 현재 해결중인 문제에 대해 질문함으로써 실수로 남용을 악화 시키지는 않지만 어떻게해야합니까? 나는 당신을 믿습니다.

주어진 트랜잭션 블록 내에서 사용자가 명시적인 '커밋'호출을 발행하지 못하게하고 싶습니다. SQL Fiddle의 컨텍스트에서 트랜잭션 블록은 오른쪽 패널에서 실행되는 코드입니다. 기본적으로 일반 텍스트 SQL 명령 목록을 반복 실행하고 있으며 배치가 끝날 때 변경 사항이 모두 롤백되도록하고 싶습니다. 일반적으로 변경 사항이 롤백되지만 때로는 텍스트 내에 명시적인 '커밋'문이 있으므로 롤백이 작동하지 않습니다. 이 명시 적 커밋은 사용자가 SQL Fiddle에서 스키마를 끊으려고 시도했을 가능성이 높으므로 해당 작업을 수행하는 다른 사람들은 오류를 보게됩니다.

Main Desired Result : 가능한 경우 JDBC 수준에서 명시 적 커밋을 비활성화하고 싶습니다. 여러 데이터베이스 백엔드 공급 업체를 지원해야하기 때문에 물론 각기 다른 수준의 단점이 있습니다.

대체 옵션 : 명시 적 커밋을 비활성화하도록 JDBC를 구성 할 수없는 경우 SQL Server, Oracle, MySQL 및 PostgreSQL과 같은 각 백엔드에 대한 배치를 처리하는 동안 명시 적 커밋을 감지하는 솔루션을 사용할 수 있습니다.

SQL Server의 경우이 솔루션을 생각했습니다. 문을 실행하기 전에 XML 쿼리 계획을 구문 분석 하고이 XPath와 일치하는 항목이 있는지 확인하십시오.

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

나는 이것이 SQL Server에서 잘 작동한다고 생각합니다. 그러나이 방법은 다른 DB 유형에서는 작동하지 않습니다. 명시 적 커밋에 대한 Oracle의 XML 실행 계획 출력은 커밋 문을 실행하고 있다는 사실을 참조하지 않습니다 (단, 커밋하는 쿼리의 실행 계획 출력을 단순히 반복 함). PostgreSQL 및 MySQL은 명시 적 커밋에 대해 실행 계획 출력 (XML 또는 기타)을 전혀 제공하지 않습니다.

그것은 "commit"이라는 단어에 대한 실제 진술을 확인하는 데 도움이됩니다. 가능한 모든 종류의 변형이있을 수 있다는 점을 제외하고는 작동합니다.

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

위의 SQL Server의 예 (해결 방법)는 Oracle, MySQL 및 PostgreSQL에서도 비슷한 일이 가능할 것입니다. 그 가정에 내가 틀렸습니까? 어쩌면 "동적"커밋 문을 허용하지 않습니까? Oracle, MySQL 및 PostgreSQL에서 비슷한 일이 발생할 수 있는지 확인하려면 SQL Fiddle (샘플 스키마 나 다른 사람이 작업하지 않을 가능성이있는)을 사용하십시오. 그렇지 않은 경우 간단한 문자열 감지가 작동 할 수 있습니다.

또 다른 가능성

또 다른 옵션이 나에게 발생했습니다.이 데이터베이스를 읽기 전용 모드로 설정하는 방법을 알고 있다면 해당 모드에서는 아무것도 커밋 할 수 없으며 작동 할 수도 있습니다. 해당 모드에서 커밋 할 수없는 한 트랜잭션을 시작하고 트랜잭션 내에서 코드를 실행할 수 있도록해야합니다. 가능합니까?

최신 정보

내가 최근에 배운 것-이것은 실제로 PostgreSQL의 문제가 아닙니다. 트랜잭션 블록 내에서 발행 된 커밋은 동일한 블록이 결국 Postgres에서 롤백되는 경우 적용되지 않습니다. Postgres에 대한 만세!

필자는 SO 게시물에 대한 링크 덕분에 Oracle에 대해 DEFERRABLE INITIALLY DEFERRED 해킹을 사용하여 내가 한 일을 달성 할 수 있다고 생각합니다 (커밋이 발행되면 오류가 발생하지만 해결할 수는 있습니다). 이것은 오라클을 다루어야합니다. (중첩 트랜잭션이 여기에서 작동 할 수 있다고 생각했지만 오라클이 중첩 트랜잭션을 지원하는 것처럼 보이지 않습니다. 어쨌든 이런 식으로 작동하는 것을 찾을 수 없었습니다).

아직 MySQL에 대한 솔루션이 없습니다. 중첩 트랜잭션을 사용하려고 시도했지만 작동하지 않는 것 같습니다. 나는 오른쪽에 SELECT를 허용하지 않거나 각 쿼리 후에 DB를 삭제 / 재생하는 것과 같이 MySQL에 대한보다 과감한 접근 방식을 심각하게 생각하고 있습니다. 그래도 좋은 소리는 아닙니다.

해결

따라서 이제 SQL Server 및 Oracle에 대해 설명 된 솔루션을 구현했으며 앞에서 언급했듯이 실제로 PostgreSQL에는 문제가되지 않습니다. MySQL의 경우 쿼리 패널을 명령문 만 선택하도록 제한하는 다소 불행한 단계를 수행했습니다. MySQL 용 DDL 및 DML은 스키마 패널 (왼쪽)에 입력하면됩니다. 나는 이것이 오래된 바이올린을 너무 많이 나누지 않기를 희망하지만 데이터 일관성을 보장하기 위해해야한다고 생각합니다. 감사!


언급할만한 가치가 있습니다. 또한 "사전 커밋"트리거에 대해 많은 연구를했습니다. 존재하지 않는 것처럼 보이므로 불행히도 옵션도 아닙니다.
Jake Feasel 2016 년

2
Oracle의 경우,이 잡기 커밋 좋은의 비열한 방법처럼 보인다 : stackoverflow.com/a/6463800/790702 그가 언급을하지 않는 무엇을 당신이 두번째 상황을 중지, 너무 코드에서 제약 조건 위반을 잡을 수 있어야한다는 것입니다 발생합니다.
Philᵀᴹ

@ 필자의 유일한 문제는 각 테이블의 정의를 제어 할 수 없으며 실제로 왼쪽 패널에 정의되어 있다는 것입니다. 따라서 DEFERRABLE INITIALLY DEFERRED 절이 없을 것입니다 (모든 테이블에 대해 자동으로 수행 할 수있는 방법이 없다면 (예 : 테이블 명령문을 생성하는 데 응답하는 시스템 트리거를 통해?)
Ugh

1
@NickChammas 커밋을 비활성화해야합니다 (왼쪽 패널에 정의 된대로) 스키마를 고정 상태로 유지할 수 있습니다. 동일한 문제를 해결하려고 시도하는 동일한 스키마에 대해 쿼리를 작성하는 사람은 얼마든지있을 수 있습니다. 그들이 서로 방해하지 않도록 구조와 데이터가 변경되지 않도록해야합니다. 이는 롤백 된 트랜잭션을 통해 수행되지만 오른쪽 코드가 커밋 된 경우에는 발생하지 않습니다.
Jake Feasel

2
@RickJames DDL은 MySQL 및 Oracle에서 암시 적 커밋을 생성하지만 PostgreSQL 또는 SQL Server에서는 생성하지 않습니다. 이 포스트 다음에 구현 한 메커니즘은 이러한 문제를 처리합니다. 임의의 SQL을 입력하는 한-그게 요점입니다!
Jake Feasel 2016 년

답변:


3

Oracle의 경우 이것은 커밋을 잡는 좋은 비열한 방법처럼 보입니다.

/programming//a/6463800/790702

그가 언급하지 않은 것은 코드에서 제약 조건 위반을 잡아서 두 번째 상황이 발생하는 것을 막을 수 있다는 것입니다.


다시 한번 감사합니다. Phil. Oracle에이 기술을 잘 활용할 수있었습니다. 다른 데이터베이스가 지연 제약 조건을 지원하기를 바랍니다.
Jake Feasel 2016 년

걱정 마. 채팅에 참여하고 인사 :)
Philᵀᴹ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.