MySQL 커밋 된 데이터가 쿼리를 선택하지 못함


13

컨텍스트 : 사용 된 프레임 워크는 Spring이며 모든 쿼리는 JdbcTemplate을 사용하여 실행됩니다. MySQL 서버 버전은 5.6.19입니다. 는 table입니다 InnoDB table및 기본 설정과 같이 auto commit격리 수준 반복-읽기를 설정합니다.

문제점 : Insert트랜잭션 내부에서 발생하고 select삽입 된 동일한 데이터를 읽는 데이터에 데이터가 표시되지 않습니다. select실행 insert 과 후 insert트랜잭션이있다 commited.

mysql에서 bin 로그와 일반 로그를 활성화했습니다. 아래 관련 로그

빈 로그 :

SET TIMESTAMP=1438265764/*!*/;
BEGIN
/*!*/;
# at 249935389
#150730 14:16:04 server id 1  end_log_pos 249935606 CRC32 0xa6aca292    Query   thread_id=40    exec_time=0     error_code=0
SET TIMESTAMP=1438265764/*!*/;
insert into user_geo_loc_latest(user_id, lat, lng) values(x,y,z) on duplicate key update lat=y, lng=z
/*!*/;
# at 249935606
#150730 14:16:06 server id 1  end_log_pos 249936255 CRC32 0x2a52c734    Query   thread_id=40    exec_time=0     error_code=0
SET TIMESTAMP=1438265766/*!*/;
INSERT INTO table(txnid) VALUES ('885851438265675046')
/*!*/;
# at 249936255
#150730 14:16:06 server id 1  end_log_pos 249936514 CRC32 0x6cd85eb5    Query   thread_id=40    exec_time=0     error_code=0
SET TIMESTAMP=1438265766/*!*/;
INSERT INTO table2(x) VALUES (y)
/*!*/;
# at 249936514
#150730 14:16:06 server id 1  end_log_pos 249936545 CRC32 0xceb9ec56    Xid = 9406873
COMMIT/*!*/;

쿼리 로그

150730 14:16:04    40 Query ...
....
40 Query     select count(*) from table where txnid = '885851438265675046'
                   40 Query     select @@session.tx_read_only
                   40 Query     INSERT INTO table(txnid) VALUES ('885851438265675046')
                   40 Query     select @@session.tx_read_only
                   40 Query     INSERT INTO table2(x) values(y)
                   40 Query     commit
....
150730 14:16:07    36 Query     select pp.*, b.create_date from table pp left join bill b on pp.bill_id = b.bill_id where pp.txnid = '885851438265675046'

흥미롭게도 First insert(249935389)는 거래의 일부가되어서는 안됩니다. 별도의 API 호출이며 완전히 관련이 없습니다. 트랜잭션과 스프링 믹싱이 될 수 있습니까? 아니면 로그를 잘못 읽고 있습니까? AFAIK는 동일한 스레드에 있기 때문에 삽입이 트랜잭션에 있음을 의미합니다.

다음 두 inserts가지는 트랜잭션의 일부이며 커밋 된 것처럼 보입니다. (249936514). 이제 커밋 후에 선택 쿼리 (일반 로그의 마지막 쿼리)가 실행되고 데이터가 표시되지 않습니다. 0 행을 반환합니다. 데이터를 고려하면 어떻게 이런 일이 일어날 수 committed있습니까? 아니면 commit스레드 40에 있지 않습니까? 스레드 ID가 없기 때문입니다.

요약하면 두 가지 질문이 있습니다.

  1. BEGINbinlog에서 INSERT INTO user_geo_loc(트랜잭션의 일부가 아닌) 이전에 있습니까? 이것은 spring / Jdbc 또는 MySql의 버그 입니까? 성공) 따라서 롤백되지 않습니다.

  2. 커밋이 선택 전에 발생하면 (커밋은 14:16:06이고 선택은 14:16:07입니다) 어떻게 선택이 트랜잭션에 의해 삽입 된 행을 반환하지 않습니까?

이것은 매우 당혹 한 일입니다. 도움을 주시면 감사하겠습니다.

참고 : 저장소 및 쿼리 로그의 쿼리는 중요한 정보를 제거하도록 편집되었습니다. 그러나 쿼리의 본질은 동일하게 유지됩니다.

편집 : 자세한 예제를 사용하여 일반 로그 및 쿼리 로그로 업데이트했습니다.


5.5에 태그를 지정했지만 5.6을 언급했습니다. 무엇 이니? 복제가 관련되어 있습니까?
Rick James

@RickJames 죄송합니다. 5.6.19입니다. 쿼리와 bin 로그의 예제로 질문을 업데이트했습니다. 또한 복제 관련 문제가 없습니다. 빈 로그를 켜서 문제를 파악한 후에 만 ​​디버그했습니다. 감사합니다
아메드 이온 Axan

고마워요. 나는 볼 수 없습니다 BEGIN또는 START TRANSACTION. 대신에 autocommit=0?를 사용하고 있습니까? (나는 begin ... commit; 트랜잭션의 범위를 명확하게한다.)
Rick James

따라서 프레임 워크 (스프링)는 트랜잭션을 관리하고 일반적으로 autocommit = 0을 설정하고 끝에 커밋합니다. 연결이 이미 해당 상태에 있었기 때문에 autocommit = 0이 표시되지 않는 것 같습니다.
Ahmed Aeon Axan

답변:


3

두 번째 질문에 대한 가설을 세우려고합니다.

커밋이 선택 전에 발생하면 (커밋은 14:16:06이고 선택은 14:16:07입니다) 어떻게 선택이 트랜잭션에 의해 삽입 된 행을 반환하지 않습니까?

트랜잭션은 Spring에서 관리합니다. 따라서 select스프링을 실행하기 전에 start transaction다른 쿼리를 실행하기 위해 연결을 이미 사용했거나 이미 사용했을 가능성이 있습니다.

테이블에 삽입을 시뮬레이션하는 첫 번째 세션을 시작합니다 t.

session1> create table t (i int auto_increment primary key);
Query OK, 0 rows affected (0,32 sec)

session1> insert into t values();
Query OK, 1 row affected (0,00 sec)

session1> select * from t;
+---+
| i |
+---+
| 1 |
+---+
1 row in set (0,00 sec)

session1> start transaction;
Query OK, 0 rows affected (0,00 sec)

session1> insert into t values();
Query OK, 1 row affected (0,00 sec)

새 세션 session2를 작성합니다. 여기서 세션 autocommit은 0으로 설정됩니다.이 새 세션에서는 선택을 실행할 때 트랜잭션이 암시 적으로 시작됩니다.

session2> set autocommit = 0;
Query OK, 0 rows affected (0,00 sec)

session2> select * from t;  -- this starts a transaction
+---+
| i |
+---+
| 1 |
+---+
1 rows in set (0,00 sec)

삽입을 커밋하려면 session1로 이동하십시오.

session1> commit;

이제 session2로 다시 이동하십시오.

session2> select * from t;
+---+
| i |
+---+
| 1 |
+---+
1 row in set (0,00 sec)

Session2가 방금 삽입 된 행을 볼 수 없습니다. commitsession2에서 a 가 발생 하면 session1에 새 행이 삽입 된 것을 볼 수 있습니다.

session2> commit
1 row in set (0,00 sec)

session2> select * from t;
+---+
| i |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0,00 sec)

일반 로그는 다음과 같습니다.

150804 14:04:10     2 Query select * from t

150804 14:04:30     1 Query start transaction
150804 14:04:39     1 Query insert into t values ()
150804 14:04:44     1 Query commit
150804 14:04:51     2 Query select * from t

150804 14:05:07     2 Query commit
150804 14:05:10     2 Query select * from t

첫 번째 행은 세션 2와 관련이 있습니다. 세션 2가 트랜잭션을 열 때입니다.

이것이 당신의 사건에서 일어나는지 모르겠습니다. connection_id 36이 다른 쿼리에 사용되었는지 일반 로그에서 확인할 수 있습니다. 알려주세요.

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