亚洲欧美日韩综合系列在线_91精品人妻一区二区_欧美大肥婆一级特大AA片_九色91视频免费观看_亚洲综合国产精品_av中文字幕在线不卡_久久精品色综合网_看黄色视频的软件_无卡无码高清中文字幕码2024_亚洲欧美日韩天堂网

SpringMVC框架中多數(shù)據(jù)源的配置問題、datasource

來源:春秋戰(zhàn)國程序猿 發(fā)布時間:2018-11-14 11:22:19 閱讀量:946

  多數(shù)據(jù)源,說白了,就是多數(shù)據(jù)庫。因為我們配置數(shù)據(jù)源需要指定特定的數(shù)據(jù)庫名稱,如下,這是我們經(jīng)常使用的配置數(shù)據(jù)源的XML文件內(nèi)容中的一部分:





<!-- 配置數(shù)據(jù)源dataSource,連接MySQL數(shù)據(jù)庫 、數(shù)據(jù)庫:learn_system -->

    <!--

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

        <property name="driverClassName"

            value="com.mysql.jdbc.Driver">

        </property>

        <property name="url"

            value="jdbc:mysql://localhost:3306/learn_system">

        </property>

        <property name="username" value="root"></property>

        <property name="password" value="root"></property>

    </bean>

    -->


這里value="jdbc:mysql://localhost:3306/learn_system"的learn_system就是我們的數(shù)據(jù)庫名稱。

如果我們需要配置多個數(shù)據(jù)源,我們就需要寫多個bean,每個bean對應(yīng)一個數(shù)據(jù)源。難點在于,如何控制多個數(shù)據(jù)源之間的切換。這里我們需要借助ThreadLocal類,這個類位于java.lang包下,首先說明ThreadLocal存放的值是線程內(nèi)共享的,線程間互斥的,主要用于線程內(nèi)共享一些數(shù)據(jù),避免通過參數(shù)來傳遞,這樣處理后,能夠優(yōu)雅的解決一些實際問題,比如:


1,Hibernate中的OpenSessionInView,就是借助ThreadLocal保存Session對象;


2,數(shù)據(jù)庫連接,借助ThreadLocal來傳遞Connection對象;




同樣的,今天我們實現(xiàn)多數(shù)據(jù)源,也要借助ThreadLocal類,通過ThreadLocal類傳遞數(shù)據(jù)源的參數(shù),我們這里傳遞的是bean的id,也就是SpringMVC中bean的名稱,通過這個id,我們就可以調(diào)用相應(yīng)的bean,這樣就實現(xiàn)了不同數(shù)據(jù)源之間的切換。


首先要明確:

 * ThreadLocal類,是什么?首先ThreadLocal不是Thread,因為如果我們要創(chuàng)建

 * 一個線程,我們需要繼承Thread類或者實現(xiàn)Runnable接口,ThreadLocal沒有

 * 繼承Thread類,也沒有繼承Runnable接口。


ThreadLocal的作用,就是將本地變量,也就是當前內(nèi)存中的變量,與線程關(guān)聯(lián)起來。




好的,廢話不多說,先上代碼:





<bean id="datasource_test" class="org.apache.commons.dbcp.BasicDataSource">

<property name="driverClassName"

value="com.mysql.jdbc.Driver">

</property>

<property name="url"

value="jdbc:mysql://localhost:3306/test">

</property>

<property name="username" value="root"></property>

<property name="password" value="root"></property>

</bean> 

 

<bean id="datasource_learn_system" class="org.apache.commons.dbcp.BasicDataSource">

<property name="driverClassName"

value="com.mysql.jdbc.Driver">

</property>

<property name="url"

value="jdbc:mysql://localhost:3306/learn_system">

</property>

<property name="username" value="root"></property>

<property name="password" value="root"></property>

</bean> 


上面配置了2個數(shù)據(jù)源:datasource_test 和 datasource_learn_system,對應(yīng)MySQL數(shù)據(jù)庫中的2個不同的數(shù)據(jù)庫;



然后我們需要寫一個類:DynamicDataSource


<span style="font-size:14px;">import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

 

/*

 * 配置多數(shù)據(jù)源

 */

 

public class DynamicDataSource extends AbstractRoutingDataSource{

 

public static final String DATASOURCE_TEST = "datasource_test";

public static final String DATASOURCE_LEARN_SYSTEM = "datasource_learn_system";

//本地線程,獲取當前正在執(zhí)行的currentThread

public static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); 

public static void setCustomerType(String customerType) {

 

        contextHolder.set(customerType);

        

    }

 

    public static String getCustomerType() {

 

        return contextHolder.get();

         

    }

 

    public static void clearCustomerType() {

 

        contextHolder.remove();

    

    }

 

@Override

protected Object determineCurrentLookupKey() {

return getCustomerType();

}

}</span>


接下來我們要在配置文件中進行配置,




    <bean id="dataSource" class="com.spring.dynamic_datasource.DynamicDataSource">

        <property name="targetDataSources">

            <map key-type="java.lang.String">

                <entry value-ref="datasource_test" key="datasource_test"></entry>

                <entry value-ref="datasource_learn_system" key="datasource_learn_system"></entry>

            </map>

        </property>

        <property name="defaultTargetDataSource" ref="datasource_learn_system"></property>

</bean>


好了,通過這些代碼,我們就可以實現(xiàn)多數(shù)據(jù)源的切換了,接下來,我們只需要在執(zhí)行數(shù)據(jù)庫操作之前,切換數(shù)據(jù)源,就可以實現(xiàn)動態(tài)切換數(shù)據(jù)庫的項目需求了。接下來看一下實例代碼:




//查詢當前用戶的所有上傳圖片

@Override

public boolean saveUploadPicture(Picture_of_user picture_of_user) {

//定義一個Boolean類型的flag,用來表示查詢狀態(tài)

boolean flag = false;

sql = "insert into picture_of_user(id,picture_name,picture_size,upload_date,picture_type,username) " +

"values(?,?,?,?,?,?);";

//切換數(shù)據(jù)源 datasource_test

//這段代碼相當于,把String類型的參數(shù) datasource_test 放在了保存到了本地線程的當前線程中,也就是當前正在執(zhí)行的線程。

DynamicDataSource.setCustomerType(DynamicDataSource.DATASOURCE_LEARN_SYSTEM);

 

int i = this.getJdbcTemplate().update(sql, new Object[]{

null,

picture_of_user.getPicture_name(),

picture_of_user.getPicture_size(),

picture_of_user.getUpload_date(),

picture_of_user.getPicture_type(),

picture_of_user.getUsername()

});

//如果插入操作執(zhí)行成功,則flag=true;否則flag=flase

if(i > 0){

//測試輸出

System.out.println("i = " + i);

flag = true;

}

else{

//測試輸出

System.out.println("i = " + i);

flag = false;

}

return flag;

}


我們只需要加上這一行代碼,就可以實現(xiàn)數(shù)據(jù)源切換了:

DynamicDataSource.setCustomerType(DynamicDataSource.DATASOURCE_LEARN_SYSTEM);




這段代碼做了什么呢?這段代碼,把當前要選擇的數(shù)據(jù)源,保存到ThreadLocal對象中。


接下來我們看一下源碼:


<span style="font-size:14px;">package com.spring.dynamic_datasource;

 

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

 

/*

 * 配置多數(shù)據(jù)源

 */

 

public class DynamicDataSource extends AbstractRoutingDataSource{

 

public static final String DATASOURCE_TEST = "datasource_test";

public static final String DATASOURCE_LEARN_SYSTEM = "datasource_learn_system";

//本地線程,獲取當前正在執(zhí)行的currentThread

public static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); 

public static void setCustomerType(String customerType) {

//把當前請求的參數(shù),存入當前線程,這個參數(shù)是我們定義的DATASOURCE_TEST 或者 DATASOURCE_LEARN_SYSTEM

//我們來看一下源碼:

//public void set(T value) {

//    Thread t = Thread.currentThread();

//    ThreadLocalMap map = getMap(t);

//    if (map != null)

//        map.set(this, value);

//    else

//        createMap(t, value);

//這段代碼的官方說明如下

    /**

     * Sets the current thread's copy of this thread-local variable

     * to the specified value.  Most subclasses will have no need to 

     * override this method, relying solely on the {@link #initialValue}

     * method to set the values of thread-locals.

     *

     * @param value the value to be stored in the current thread's copy of

     *        this thread-local.

     */

        //測試輸出

        System.out.println("當前切換的數(shù)據(jù)源 = " + customerType);

 

        contextHolder.set(customerType);

        

    }

 

    public static String getCustomerType() {

 

    //官方文檔如下:

 

        /**

         * Returns the value in the current thread's copy of this

         * thread-local variable.  If the variable has no value for the

         * current thread, it is first initialized to the value returned

         * by an invocation of the {@link #initialValue} method.

         *

         * @return the current thread's value of this thread-local

         */

        //public T get() {

            //Thread t = Thread.currentThread();

            //ThreadLocalMap map = getMap(t);

            //if (map != null) {

                //ThreadLocalMap.Entry e = map.getEntry(this);

                //if (e != null)

              //      return (T)e.value;

            //}

          //  return setInitialValue();

        //}

        return contextHolder.get();

         

    }

 

    public static void clearCustomerType() {

 

        /**

         * Removes the current thread's value for this thread-local

         * variable.  If this thread-local variable is subsequently

         * {@linkplain #get read} by the current thread, its value will be

         * reinitialized by invoking its {@link #initialValue} method,

         * unless its value is {@linkplain #set set} by the current thread

         * in the interim.  This may result in multiple invocations of the

         * <tt>initialValue</tt> method in the current thread.

         *

         * @since 1.5

         */

    //源代碼如下:

         //public void remove() {

           //  ThreadLocalMap m = getMap(Thread.currentThread());

             //if (m != null)

               //  m.remove(this);

         //}

        contextHolder.remove();

    

    }

 

@Override

protected Object determineCurrentLookupKey() {

return getCustomerType();

}

 

}</span>



public class ThreadLocal<T> 類沒有繼承其他類,只是間接繼承了Object類,我們來看一下官方對這個類的使用說明:



/**

 * This class provides thread-local variables.  These variables differ from

 * their normal counterparts in that each thread that accesses one (via its

 * <tt>get</tt> or <tt>set</tt> method) has its own, independently initialized

 * copy of the variable.  <tt>ThreadLocal</tt> instances are typically private

 * static fields in classes that wish to associate state with a thread (e.g.,

 * a user ID or Transaction ID).

 *

 * <p>For example, the class below generates unique identifiers local to each

 * thread.

 * A thread's id is

 * assigned the first time it invokes <tt>UniqueThreadIdGenerator.getCurrentThreadId()</tt> and remains unchanged on subsequent calls.

 * <pre>

 * import java.util.concurrent.atomic.AtomicInteger;

 *

 * public class UniqueThreadIdGenerator {

 *

 *     private static final AtomicInteger uniqueId = new AtomicInteger(0);

 *

 *     private static final ThreadLocal < Integer > uniqueNum = 

 *         new ThreadLocal < Integer > () {

 *             @Override protected Integer initialValue() {

 *                 return uniqueId.getAndIncrement();

 *         }

 *     };

 * 

 *     public static int getCurrentThreadId() {

 *         return uniqueId.get();

 *     }

 * } // UniqueThreadIdGenerator

 * </pre>

 * <p>Each thread holds an implicit reference to its copy of a thread-local

 * variable as long as the thread is alive and the <tt>ThreadLocal</tt>

 * instance is accessible; after a thread goes away, all of its copies of

 * thread-local instances are subject to garbage collection (unless other

 * references to these copies exist). 

 *

 * @author  Josh Bloch and Doug Lea

 * @version 1.42, 06/23/06

 * @since   1.2

 */


最后還是要重復(fù)說明:


 * ThreadLocal類,是什么?首先ThreadLocal不是Thread,因為如果我們要創(chuàng)建

 * 一個線程,我們需要繼承Thread類或者實現(xiàn)Runnable接口,ThreadLocal沒有

 * 繼承Thread類,也沒有繼承Runnable接口。




ThreadLocal做了什么?ThreadLocal的作用,就是將本地變量,也就是當前內(nèi)存中的變量,與線程關(guān)聯(lián)起來,就像官方描述文檔中說的:


 * ThreadLocal provides thread-local variables.  These variables differ from

 * their normal counterparts in that each thread that accesses one has its own, independently initialized

 * copy of the variable.  ThreadLocal instances are typically private

 * static fields in classes that wish to associate state with a thread (e.g.,

 * a user ID or Transaction ID).




思考:如果我們需要配置3個數(shù)據(jù)源,該如何操作呢?其實很簡單,我們只需要再配置一個數(shù)據(jù)源就可以了。


思考:如果我們在項目中使用不同的數(shù)據(jù)庫系統(tǒng),比如MySQL、Oracle,該如何操作呢?同理,我們只需要對數(shù)據(jù)源的配置參數(shù)進行修改就可以了。




好了,關(guān)于多數(shù)據(jù)源的配置,就說到這里。接下來會給大家測試幾個多數(shù)據(jù)源配置的實例。理論上可行的,還要經(jīng)過實踐檢驗。

--------------------- 


分享:
評論:
你還沒有登錄,請先