? ? 使用Mycat用于讀寫分離時,對數(shù)據(jù)庫的事務不跨庫,如果硬要打開事務沒有關閉的話,容易產(chǎn)生系統(tǒng)事務紊亂等問題。通過源代碼仔細分析,發(fā)現(xiàn)mycat并非透傳sql語句。
? ?start transaction的處理
public final class StartHandler {
? ? private static final byte[] AC_OFF = new byte[] { 7, 0, 0, 1, 0, 0, 0, 0,
? ? ? ? ? ? 0, 0, 0 };
? ? public static void handle(String stmt, ServerConnection c, int offset) {
? ? ? ? switch (ServerParseStart.parse(stmt, offset)) {
? ? ? ? case ServerParseStart.TRANSACTION:
? ? ? ? ? ? if (c.isAutocommit())
? ? ? ? ? ? {
? ? ? ? ? ? ? ? c.setAutocommit(false);
? ? ? ? ? ? ? ? c.write(c.writeToBuffer(AC_OFF, c.allocate()));
? ? ? ? ? ? }else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? c.getSession2().commit() ;
? ? ? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? c.execute(stmt, ServerParse.START);
? ? ? ? }
? ? }
}
也就是說,mycat把start transaction 改成了set commit=0,而且不是立即發(fā)送給后端mysql
2019-11-19T01:43:01.970695Z? ? ?5 Query SET autocommit=0;
2019-11-19T01:43:01.970695Z ? ? 5 Query update city set Name='MJMJ' where id=1
2019-11-19T01:43:06.907978Z ? ? 5 Query commit
2019-11-19T01:43:06.953980Z ? ? 5 Query rollback
2019-11-19T01:43:19.846718Z ? ? 5 Query SET autocommit=1;
2019-11-19T01:43:19.846718Z ? ? 5 Query select * from city where id = 1
前兩條是一起送給mysql的。如果事務沒有關閉,導致整個連接的autocommit屬性的改變。
多了一個rollback
從上面一個簡單的事務,可以發(fā)現(xiàn)每次commit后面都會跟著一個rollback
通過分析源代碼NoBlockingSession.java發(fā)現(xiàn)
public void releaseConnection(RouteResultsetNode rrn, boolean debug, final boolean needRollback) {
BackendConnection c = target.remove(rrn);
if (c != null) {
if (debug) {
LOGGER.debug("release connection " + c);
}
if (c.getAttachment() != null) {
c.setAttachment(null);
}
if (!c.isClosedOrQuit()) {
if (c.isAutocommit()) {
c.release();
} //else if (needRollback) {
c.setResponseHandler(new RollbackReleaseHandler());
c.rollback();
} //else {
c.release();
}
}
}
}
needRollback的判斷竟然被注釋掉了,實在令人費解啊!
至此,mycat單node簡單事務問題終于研究清楚了。