myBatis多數據源連接
1、首先得有一個Springmvc + Spring + Mybatis maven項目
2、編輯一個擴展AbstractRoutingDataSource類,DynamicDataSource.java重寫determineCurrentLookupKey()方法。
3、 封裝一個的對數據源進行操作的類,DbContextUtils.java
使用ThreadLocal維護變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。
從線程的角度看,目標變量就象是線程的本地變量,這也是類名中“Local”所要表達的意思。
ThreadLocal的接口方法
ThreadLocal類接口很簡單,只有4個方法,我們先來了解一下:
① void set(Object value)設置當前線程的線程局部變量的值。
② public Object get()該方法返回當前線程所對應的線程局部變量。
③ public void remove()將當前線程局部變量的值刪除,目的是為了減少內存的占用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束后,對應該線程的局部變量將自動被垃圾回收,所以顯式調用該方法清除線程的局部變量並不是必須的操作,但它可以加快內存回收的速度。
④ protected Object initialValue()返回該線程局部變量的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,在線程第1次調用get()或set(Object)時才執行,並且僅執行1次。ThreadLocal中的缺省實現直接返回一個null。
4、應用spring aop來設置,把配置的數據源類型都設置成為注解標簽,在service層中需要切換數據源的方法上,寫上注解標簽,調用相應方法切換數據源.
4.1、編輯注解標簽TargetDataSource.java
注解說明
RetentionPolicy.RUNTIME —— 這種類型的Annotations將被JVM保留,所以他們能在運行時被JVM或其他使用反射機制的代碼所讀取和使用。
Documented 注解表明這個注解應該被 javadoc工具記錄. 默認情況下,javadoc是不包括注解的. 但如果聲明注解時指定了 @Documented,則它會被 javadoc 之類的工具處理, 所以注解類型信息也會被包括在生成的文檔中。
@Target說明了Annotation所修飾的對象范圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
4.2、編輯切面的Bean,AspectTargetDataSource.java
@Pointcut("@annotation(com.tynet.service.TargetDataSource)")
攔截帶有@TargetDataSource注解的方法。
@Before(value="setTargetDataSource() && @annotation(dataSource)")
前置任務中dataSource 指的是自定義切面注解上所附帶的參數。
5、配置配置文件
我這只顯示兩個,實際上可以連接很多數據源,只需要增加bean然后把id加入map中,我的默認的數據庫是db_plat。
6、記得聲明自動為spring容器中那些配置@aspectJ切面的bean創建代理,織入切面。
7、在方法上加上注解即可使用。
8、實現原理
擴展Spring的AbstractRoutingDataSource抽象類。
該類充當了DataSource的路由中介, 能有在運行時, 根據某種key值來動態切換到真正的DataSource上。
看AbstractRoutingDataSource的源碼:
它繼承了AbstractDataSource,而AbstractDataSource正是javax.sql.DataSource的子類。
Java中數據庫有很多連接方式,在眾多方式中除了JDBC外都有DataSource對象。
DataSource可以看作數據源,它封裝了數據庫參數,連接數據庫,程序中操作DataSource對象即可對數據庫進行增刪改查操作。
分析下AbstractRoutingDataSource實現DataSource的getConnection方法:
看來重點是determineTargetDataSource()方法,上源碼:
看注解,檢索當前目標的數據源。
重點在於determineCurrentLookupKey()方法。
可以看到如果當前線程變量沒有值,它首先被初始化為默認的值。
determineCurrentLookupKey()是AbstractRoutingDataSource類中的一個抽象方法,而它的返回值是當前線程要用的數據源dataSource的key值,有了這個key值,resolvedDataSource(這是個map,由配置文件中設置好后存入的)就從中取出對應的DataSource,如果找不到,就用配置默認的數據源。
而我們上面的所有操作都是要擴展AbstractRoutingDataSource類,並重寫其中的determineCurrentLookupKey()方法,來實現數據源的切換。