寫代碼中的某一天,我寫下了如下的代碼:
public Connection getConn() { String driver = "com.mysql.jdbc.Driver"; String url = "***"; String username = "***"; String password = "***"; Connection conn = null; PreparedStatement pst = null; try { Class.forName(driver); //classLoader,加載對應驅動
conn = (Connection) DriverManager.getConnection(url, username, password);
String sql = "select * from info info , info_extend extend where info.id = extend.infoid "
+ " order by (CASE WHEN info.pid=1006 THEN 1 ELSE 0 END) asc ,(CASE WHEN info.pid = 1006 THEN info.intext ELSE extend.intext END) desc "
+ " limit 0,10";
System.out.println(sql);
pst = (PreparedStatement) conn.prepareStatement(sql);//准備執行語句
ResultSet rs = pst.executeQuery(); while(rs.next()){ System.out.println(rs.getString(1)+"-----"+rs.getString(2) + "-----" + rs.getString(3) + "----" + rs.getString(4)); } } catch (Exception e) { e.printStackTrace(); } return conn; }
很明顯,上面這段sql是連表查詢了兩張表 info 和 extend ,有兩個字段進行order by ,如果pid=1006的話那就排在上面,如果pid不是1006那就按extend表的intext字段來排序,我們可以認為這兩個order by 是沒有問題的。
但是查詢出來的結果就存在一點奇怪了,請看!
第一次執行:
第二次執行,在看:
請注意細看,兩次執行的數據的順序發生了改變。雖然他還是按照我們的orderby的順序排的(只是在intext值一樣的時候,他就開始隨機的排序了)
看到了吧,同一段sql居然會有不一樣的結果(),是不是很奇葩~
我覺得很奇怪,就把sql粘下來,拿到mysql客戶端去執行,結果如下
無論執行多少次,他們的順序也不會發生變化。這就真的很奇怪了,sql都是一樣的,為什么就會有不一樣的結果呢。
查詢了很多資料,也沒找到一個比較確認的理由,只是較多人認為是由於緩存的存在。
引用一下別人的回答:
“
根數據庫系統的算法有關,早期版本的算法是自然的多個線程二分法,那個線程先查到滿足條件的數據就先輸出出來,這樣就是亂序的,后期經過改進按照主鍵自然排序輸出。
如果order by的值相同,一般是按自然排序,就是首個字符的字母或漢字的發音的首字母的s排序。
”
order by的字段自然排序,如果你的order by 字段是resort,resort值相同的情況下,是可能有兩種結果,一種就是你列出的隨機排序,還有一種就是按主鍵來排序。這個問題不是固定的,還可能跟你的服務器性能都有關系,如果內存足夠大,執行mysql的時候會提供足夠大的緩沖池,也可能會出現另一種結果。
所以很有可能是因為緩存的存在,在mysql客戶端存在緩存,然后每一次查詢都走緩存所以他的順序不會發生改變。然而執行java程序順序不一致,可能就是因為沒有走緩存,每一次都是實時查詢。也許java程序的這種結果本身就具有更多的可靠性。
還有一個很奇怪的現象:有時候java程序的結果是不會變的,有時候就是會發生變化的。這一點很令人疑惑,但同時也更肯定了緩存的因素。
那如何解決這個問題?
很簡單,他不是順序有時會不一致嗎,那我們再給他一個順序進行排序就好了。在order by 后面加上 id desc , 那么我們的查詢結果就是一致了的。