import java.sql.Connection; import java.sql.ResultSet; import java.util.Properties; import com.mysql.jdbc.ReplicationDriver; public class ReplicationDriverDemo { public static void main(String[] args) throws Exception { ReplicationDriver driver = new ReplicationDriver(); Properties props = new Properties(); // We want this for failover on the slaves props.put("autoReconnect", "true"); // We want to load balance between the slaves props.put("roundRobinLoadBalance", "true"); props.put("user", "foo"); props.put("password", "bar"); // // Looks like a normal MySQL JDBC url, with a // comma-separated list of hosts, the first // being the 'master', the rest being any number // of slaves that the driver will load balance against // Connection conn = driver.connect("jdbc:mysql:replication://master,slave1,slave2,slave3/test", props); // // Perform read/write work on the master // by setting the read-only flag to "false" // conn.setReadOnly(false); conn.setAutoCommit(false); conn.createStatement().executeUpdate("UPDATE some_table ...."); conn.commit(); // // Now, do a query from a slave, the driver automatically picks one // from the list // conn.setReadOnly(true); ResultSet rs = conn.createStatement().executeQuery("SELECT a,b FROM alt_table"); ....... } }
MySQL 提供支持讀寫分離的驅動類:java
com.mysql.jdbc.ReplicationDriver
替代mysql
com.mysql.jdbc.Driver
注意,全部參數主從統一:web
jdbc:mysql:replication://<master>,<slave>.../...?...=...
固然,用戶名和密碼也必須相同spring
觸發Slave的狀況sql
設置 auto_commit = false安全
設置 readOnly 爲 trueapp
綜上特色,讀寫分離依賴於事務ide
經常使用使用場景:測試
第一種, 事務管理使用【註解】支持ui
一般,事務管理在Service層,只須要簡單的操做便可支持讀寫分離:
1 2 |
|
事務開啓後,查詢自動切換到從庫。
注意:@Transactional 默認的readOnly參數是false,更新操做不須要特別的改動。propagation是指的事務傳播方式,默認設置是Require,指的是「本次操做須要事務支持,若是沒有事務開啓一個事務,若是有事務,加入到該事務中」
考慮複雜一點的狀況,當Service中出現自我方法的調用時:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
當外部調用getOrder時,getOrder方法的@Transaction註解生效,設置從庫查詢。
當外部調用updateOrder時,updateOrder方法的@Transaction註解生效,設置操做主庫。
注意,這兩個方法都調用了findSubOrderList方法,而調用的對象是this,不是被spring事務管理器替換過的service對象,因此findSubOrderList方法上的@Transaction註解無效,會根據上文環境來查主庫和從庫
這種特性對於業務來講是恰當好處的,生效的事務是在最外層的方法上,能夠避免在一個事務內部出現讀寫庫不統一的狀況。
更復雜一點的狀況,當service中調用了其它類的service:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
1, 當外部調用OrderSerivce的getOrder時,getOrder方法的@Transaction註解生效,設置從庫查詢。
getOrder內部調用了OrderCouponService的getById方法,因爲orderCouponService是spring提供的對象,通過了事務管理,因此getById方法上的@Transaction註解生效,
咱們知道Require這個事務傳播的特性,getById不會建立新的事務,因此依舊是由從庫讀取數據。
2, 當外部調用OrderSerivce的saveOrder時,saveOrder方法的@Transaction註解生效,設置操做主庫。
saveOrder內部調用了OrderCouponService的saveCoupon方法,一樣因爲Require的特性,沒有建立新事務,操做主庫。
3, 當外部調用OrderSerivce的updateOrder時,updateOrder方法的@Transaction註解生效,設置操做主庫。
updateOrder內部調用了OrderCouponService的getById方法,一樣因爲Require的特性,沒有建立新事務,從主庫讀出數據。
這些特性也是很好的,咱們只須要關心最外部調用的方法的註解內容,就能夠肯定走的哪一個庫。
更復雜點的狀況是新開事務的狀況,建議謹慎對待
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
該想法是構想把OrderSerivce的getOrderPrice查詢走從庫,其中一個小邏輯更新庫設置操做主庫。在沒有設置主從的狀況下,這種方式是支持的,並不會出現問題。
但在設置了主從的狀況下,這種業務邏輯操做就「不安全」了,由於,updateById走的是主庫,它的更新操做是依賴於主從同步的,頗有可能getById取到了「過時」的數據。
這種狀況在業務上來講是應該要避免的,若是不能避免,最好的辦法是讓外部都走主庫,保證數據來源的一致性。
綜上,事務管理配置用註解的方式仍是蠻方便的。
第二種, 事務管理使用【XML配置】支持
XML配置的事務是以判斷指定名稱開頭的方法來實現的,跟註解配置事務是相似的。能夠把select和get斷定爲readOnly,傳播機制設定爲Require。
第三種,使用支持讀事務的入口類
鑑於現有代碼Service層被融合到web和admin中,在Service層的注入會影響多個系統,而單獨寫方法,難免繁瑣,使用代理方法支持事務的讀比較靈活。
流程:
這個模式好處在於能夠根據業務的須要,合理安排開發和測試的工做,影響範圍可控。
實現代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
|
按需配置:
1 2 3 4 5 |
|
使用時請注意:原有@Autowired方式注入請改爲@Resource指定名稱的方式,以區別不一樣入口
1 2 3 4 5 |
|