为什么myBatis+postgresql 9.3 查询成功了还是回滚?
Why does myBatis+postgresql 9.3 issue a ROLLBACK even if the query succeeds?
我有一段 Java 使用 myBatis、postgresql 9.3 服务器和 postgresql-9.3-1100-jdbc41 JDBC 驱动程序的代码。
我们还使用 mybatis-guice 来支持@Transactional。
直到现在我们一直只使用可序列化的事务,现在我们想把只从数据库读取的查询放在一个不太严格的隔离级别,比如 'read committed'。所以,有些@Transactional 注解使用SERIALIZABLE,有些使用READ_COMMITTED。还有嵌套调用。
所以,我在 postgresql 服务器日志中有这个:
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1268 txnId=0 pid=1949 appName=entity_manager LOG: execute : SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=0 pid=1949 appName=entity_manager LOG: execute : BEGIN
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=0 pid=1949 appName=entity_manager LOG: execute : SELECT
*
FROM
customer.accounts
WHERE
--
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=0 pid=1949 appName=entity_manager LOG: execute : UPDATE
customer.cities
SET
name = ,
ledger_id = ,
--
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=0 pid=1949 appName=entity_manager DETAIL: parameters: ......
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager LOG: execute : SELECT
l.*
,
cc.id as cost_center_id,
cc.description as cost_center_description,
--
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager DETAIL: parameters: = .....
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager LOG: execute : UPDATE
customer.ledgers
SET
internal_ledger_number =
,
--
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager DETAIL: parameters: = ...........
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager LOG: execute : SELECT DISTINCT
role
FROM customer.user_roles ur INNER JOIN customer.user_to_accounts_to_user_roles uur ON (ur.id=uur.role_id)
WHERE
user_id=
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager DETAIL: parameters: = .......
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager LOG: execute S_2: ROLLBACK
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager LOG: execute : BEGIN
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager LOG: execute : SELECT
id
FROM
customer.user_roles
WHERE role=
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager DETAIL: parameters: = ......
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager LOG: execute : INSERT INTO customer.user_to_accounts_to_user_roles
(user_id, account_id, role_id)
values
(, , )
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager DETAIL: parameters: = ........
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=1726979 pid=1949 appName=entity_manager LOG: execute S_1: COMMIT
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1271 txnId=0 pid=1949 appName=entity_manager LOG: execute : SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1272 txnId=0 pid=1949 appName=entity_manager LOG: execute : BEGIN
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1272 txnId=0 pid=1949 appName=entity_manager LOG: execute : SELECT
*
FROM
customer.cities
WHERE
--
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1272 txnId=0 pid=1949 appName=entity_manager DETAIL: parameters: = ......
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1272 txnId=0 pid=1949 appName=entity_manager LOG: execute S_1: COMMIT
(这是一个片段,通过 grepping sessionId 和使用 --after-context 进行过滤——这就是为什么有些查询似乎没有终止,但请相信我,它们是有效的查询)。
所以我有一个成功查询的列表,并且在某个时候发出了 ROLLBACK。然后代码继续执行其余查询。所以我在代码中似乎没有任何异常。 ROLLBACK 似乎是突然发出的。
怎么会这样?
这种情况发生了 10 次中的 1 次,10 次中的 9 次一切正常(使用相同的数据)。代码是多线程的。
我可以提供其他细节,没问题。
同时我找到了原因。
事实证明,在一个用@Transactional 注释的方法(我们称之为方法A)中还有另一个方法也用@Transactional 注释(我们称之为方法B)。这个内部方法(methodB)抛出了一个异常,异常在 methodA 中被抛出,代码愉快地继续下去。但是,一旦 myBatis 看到异常,它就会回滚整个事务。
像这样:
methodA (@Transactional)
begin
select * ....
update .....
methodB: select ....
methodB: throw exception -> myBatis calls rollback
methodA: catch exception, go on
methodA: other code
我有一段 Java 使用 myBatis、postgresql 9.3 服务器和 postgresql-9.3-1100-jdbc41 JDBC 驱动程序的代码。 我们还使用 mybatis-guice 来支持@Transactional。 直到现在我们一直只使用可序列化的事务,现在我们想把只从数据库读取的查询放在一个不太严格的隔离级别,比如 'read committed'。所以,有些@Transactional 注解使用SERIALIZABLE,有些使用READ_COMMITTED。还有嵌套调用。
所以,我在 postgresql 服务器日志中有这个:
2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1268 txnId=0 pid=1949 appName=entity_manager LOG: execute : SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=0 pid=1949 appName=entity_manager LOG: execute : BEGIN 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=0 pid=1949 appName=entity_manager LOG: execute : SELECT * FROM customer.accounts WHERE -- 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=0 pid=1949 appName=entity_manager LOG: execute : UPDATE customer.cities SET name = , ledger_id = , -- 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=0 pid=1949 appName=entity_manager DETAIL: parameters: ...... 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager LOG: execute : SELECT l.* , cc.id as cost_center_id, cc.description as cost_center_description, -- 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager DETAIL: parameters: = ..... 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager LOG: execute : UPDATE customer.ledgers SET internal_ledger_number = , -- 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager DETAIL: parameters: = ........... 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager LOG: execute : SELECT DISTINCT role FROM customer.user_roles ur INNER JOIN customer.user_to_accounts_to_user_roles uur ON (ur.id=uur.role_id) WHERE user_id= 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager DETAIL: parameters: = ....... 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1269 txnId=1726978 pid=1949 appName=entity_manager LOG: execute S_2: ROLLBACK 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager LOG: execute : BEGIN 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager LOG: execute : SELECT id FROM customer.user_roles WHERE role= 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager DETAIL: parameters: = ...... 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager LOG: execute : INSERT INTO customer.user_to_accounts_to_user_roles (user_id, account_id, role_id) values (, , ) 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=0 pid=1949 appName=entity_manager DETAIL: parameters: = ........ 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1270 txnId=1726979 pid=1949 appName=entity_manager LOG: execute S_1: COMMIT 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1271 txnId=0 pid=1949 appName=entity_manager LOG: execute : SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1272 txnId=0 pid=1949 appName=entity_manager LOG: execute : BEGIN 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1272 txnId=0 pid=1949 appName=entity_manager LOG: execute : SELECT * FROM customer.cities WHERE -- 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1272 txnId=0 pid=1949 appName=entity_manager DETAIL: parameters: = ...... 2016-02-09 15:27:47 CET sessionId=56b9f455.79d sessionStart=2016-02-09 15:14:45 CET vTxnId=12/1272 txnId=0 pid=1949 appName=entity_manager LOG: execute S_1: COMMIT
(这是一个片段,通过 grepping sessionId 和使用 --after-context 进行过滤——这就是为什么有些查询似乎没有终止,但请相信我,它们是有效的查询)。 所以我有一个成功查询的列表,并且在某个时候发出了 ROLLBACK。然后代码继续执行其余查询。所以我在代码中似乎没有任何异常。 ROLLBACK 似乎是突然发出的。
怎么会这样?
这种情况发生了 10 次中的 1 次,10 次中的 9 次一切正常(使用相同的数据)。代码是多线程的。
我可以提供其他细节,没问题。
同时我找到了原因。
事实证明,在一个用@Transactional 注释的方法(我们称之为方法A)中还有另一个方法也用@Transactional 注释(我们称之为方法B)。这个内部方法(methodB)抛出了一个异常,异常在 methodA 中被抛出,代码愉快地继续下去。但是,一旦 myBatis 看到异常,它就会回滚整个事务。
像这样:
methodA (@Transactional)
begin
select * ....
update .....
methodB: select ....
methodB: throw exception -> myBatis calls rollback
methodA: catch exception, go on
methodA: other code