好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

mysql+spring+mybatis实现数据库读写分离的代码配置

场景:一个读数据源一个读写数据源。

原理:借助spring的【 org.springframework.jdbc.datasource.lookup.abstractroutingdatasource 】这个抽象类实现,看名字可以了解到是一个路由数据源的东西,这个类中有一个方法

?

1

2

3

4

5

6

7

8

/**

  * determine the current lookup key. this will typically be

  * implemented to check a thread-bound transaction context.

  * <p>allows for arbitrary keys. the returned key needs

  * to match the stored lookup key type, as resolved by the

  * {@link #resolvespecifiedlookupkey} method.

  */

protected abstract object determinecurrentlookupkey();

每次去连数据库的时候,spring会调用这个方法去找对应的数据源。返回值即对应的数据源的lookupkey.那么这个lookupkey在哪定义的呢?看下面的 database.xml 的配置

?

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

<!--数据源 读写 -->

<bean id= "datasourcerw" class = "org.logicalcobwebs.proxool.proxooldatasource" >

   <property name= "alias" value= "ihotelrw" ></property>

   <property name= "delegateproperties" >

     <value>user=${jdbc.username},password=${jdbc.password}

     </value>

   </property>

   <property name= "user" value= "${jdbc.username}" />

   <property name= "password" value= "${jdbc.password}" />

   <property name= "driver" value= "${jdbc.driverclassname}" />

   <property name= "driverurl" value= "${jdbc.url}" />

   <property name= "maximumconnectioncount" value= "${jdbc.maximumconnectioncount}" ></property>

   <property name= "maximumactivetime" value= "${jdbc.maximumactivetime}" ></property>

   <property name= "maximumconnectionlifetime" value= "${jdbc.maximumconnectionlifetime}" ></property>

   <property name= "prototypecount" value= "${jdbc.prototypecount}" ></property>

   <property name= "housekeepingsleeptime" value= "${jdbc.housekeepingsleeptime}" ></property>

   <property name= "simultaneousbuildthrottle" value= "${jdbc.simultaneousbuildthrottle}" ></property>

   <property name= "housekeepingtestsql" value= "${jdbc.housekeepingtestsql}" ></property>

   <property name= "verbose" value= "${jdbc.verbose}" ></property>

   <property name= "statistics" value= "${jdbc.statistics}" ></property>

   <property name= "statisticsloglevel" value= "${jdbc.statisticsloglevel}" ></property>

</bean>

   <!--数据源 读-->

   <bean id= "datasourcer" class = "org.logicalcobwebs.proxool.proxooldatasource" >

     <property name= "alias" value= "ihotelr" ></property>

     <property name= "delegateproperties" >

       <value>user=${jdbc.r.username},password=${jdbc.r.password}

       </value>

     </property>

     <property name= "user" value= "${jdbc.r.username}" />

     <property name= "password" value= "${jdbc.r.password}" />

     <property name= "driver" value= "${jdbc.r.driverclassname}" />

     <property name= "driverurl" value= "${jdbc.r.url}" />

     <property name= "maximumconnectioncount" value= "${jdbc.maximumconnectioncount}" ></property>

     <property name= "maximumactivetime" value= "${jdbc.maximumactivetime}" ></property>

     <property name= "maximumconnectionlifetime" value= "${jdbc.maximumconnectionlifetime}" ></property>

     <property name= "prototypecount" value= "${jdbc.prototypecount}" ></property>

     <property name= "housekeepingsleeptime" value= "${jdbc.housekeepingsleeptime}" ></property>

     <property name= "simultaneousbuildthrottle" value= "${jdbc.simultaneousbuildthrottle}" ></property>

     <property name= "housekeepingtestsql" value= "${jdbc.housekeepingtestsql}" ></property>

     <property name= "verbose" value= "${jdbc.verbose}" ></property>

     <property name= "statistics" value= "${jdbc.statistics}" ></property>

     <property name= "statisticsloglevel" value= "${jdbc.statisticsloglevel}" ></property>

   </bean>

   <!-- 动态数据源 -->

   <bean id= "dynamicdatasource" class = "com.dao.datasource.dynamicdatasource" >

     <!-- 通过key-value关联数据源 -->

     <property name= "targetdatasources" >

       <map>

         <entry value-ref= "datasourcerw" key= "datasourcekeyrw" ></entry>

         <entry value-ref= "datasourcer" key= "datasourcekeyr" ></entry>

       </map>

     </property>

     <property name= "defaulttargetdatasource" ref= "datasourcerw" />  

   </bean>

<!--mybatis与spring整合 开始 -->

<bean id= "sqlsessionfactory" name= "sqlsessionfactory"

   class = "org.mybatis.spring.sqlsessionfactorybean" >

   <property name= "configlocation" value= "classpath:conf/core/sqlmapconfig.xml" />

   <property name= "datasource" ref= "dynamicdatasource" />

</bean>

动态数据源dynamicdatasource中的datasourcekeyrw、datasourcekeyr就是

?

1

protected abstract object determinecurrentlookupkey();

这个方法要返回的值。那么如何设置,让这个方法的返回值是根据我们的需要返回datasourcekeyrw、datasourcekeyr呢?由于这个方法没有入参,并且是spring自动调用的,因此考虑使用静态变量存储datasource的key,在调用sql语句前设置静态变量的值,然后在这个方法中得到静态变量的值,返回。又考虑到多线程,同时可能会有很多请求,为避免线程之间相互干扰,考虑使用threadlocal。

先看存储datasourcekey的容器类。

?

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

public class dbcontextholder {

   /**

    * 线程threadlocal

    */

   private static threadlocal<string> contextholder = new threadlocal<>();

   private string db_type_rw = "datasourcekeyrw" ;

   private string db_type_r = "datasourcekeyr" ;

   public string getdbtype() {

     string db = contextholder.get();

     if (db == null ) {

       db = db_type_rw; // 默认是读写库

     }

     return db;

   }

   /**

    * 设置本线程的dbtype

    * @param str

    * @see [相关类/方法](可选)

    * @since [产品/模块版本](可选)

    */

   public void setdbtype(string str) {

     contextholder.set(str);

   }

   /**

    * cleardbtype

    * @title: cleardbtype

    * @description: 清理连接类型

    */

   public static void cleardbtype() {

     contextholder.remove();

   }

}

动态数据源的实现类。

?

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

public class dynamicdatasource extends abstractroutingdatasource {

   /*

    * (non-javadoc)

    * @see javax.sql测试数据mondatasource#getparentlogger()

    */

   @override

   public logger getparentlogger() throws sqlfeaturenotsupportedexception {

     // todo auto-generated method stub

     return null;

   }

   /**

    * override determinecurrentlookupkey

    * <p>

    * title: determinecurrentlookupkey

    * </p>

    * <p>

    * description: 自动查找datasource

    * </p>

    * @return

    */

   @override

   protected object determinecurrentlookupkey() {

     return dbcontextholder.getdbtype();

   }

}

在dao层中设置数据库类型。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

/**

    * 添加邮件

    * @param sms

    * @return

    */

   public boolean insertemail(email email) {

     //根据具体需要设置不同的数据库

     dbcontextholder.setdbtype(dbcontextholder.db_type_rw);

     //dbcontextholder.setdbtype(dbcontextholder.db_type_r);

     int result = this .getsqlsession().insert(statement + ".addentity" ,

         email);

     return result == 1 ;

   }

在本例中,我们是在dao中指定数据库,我们也可以根据需要在service或者controller中指定db类型,需要记住的是setdbtype是针对线程维度的。要考虑多线程的问题。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接

原文链接:https://blog.csdn.net/qq_26562641/article/details/64122643

查看更多关于mysql+spring+mybatis实现数据库读写分离的代码配置的详细内容...

  阅读:19次