【架构】 hibernate读写分离

  • Post author:
  • Post category:其他


转自:

Spring+Hibernate框架下MySql读写分离,主从数据库配置


介绍下mysql数据库读写分离在spring,hibernate框架下的配置。




1.mysql连接配置文件jdbc.properties




master.*.*表示主数据库连接参数,负责增,删,改;




slave.*.*表示从数据库连接参数,只负责读取;






jdbc.properties


Java代码

master.jdbc.driverClassName=com.mysql.jdbc.Driver

master.jdbc.url=********

master.jdbc.username=********

master.jdbc.password=********

slave.jdbc.driverClassName=com.mysql.jdbc.Driver

slave.jdbc.url=********

slave.jdbc.username=********

slave.jdbc.password=********



  1. master.jdbc.driverClassName=com.mysql.jdbc.Driver


  2. master.jdbc.url=********

  3. master.jdbc.username=********

  4. master.jdbc.password=********


  5. slave.jdbc.driverClassName=com.mysql.jdbc.Driver

  6. slave.jdbc.url=********

  7. slave.jdbc.username=********

  8. slave.jdbc.password=********


把**改成你所需的连接参数;






2.配置AOP切面类 DataSourceAdvice.java


Java代码

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

import org.springframework.aop.MethodBeforeAdvice;

import org.springframework.aop.ThrowsAdvice;

import com.company.datasource.DataSourceSwitcher;

public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {

// service方法执行之前被调用

public void before(Method method, Object[] args, Object target) throws Throwable {

System.out.println(“切入点: ” + target.getClass().getName() + “类中” + method.getName() + “方法”);

if(method.getName().startsWith(“add”)

|| method.getName().startsWith(“create”)

|| method.getName().startsWith(“save”)

|| method.getName().startsWith(“edit”)

|| method.getName().startsWith(“update”)

|| method.getName().startsWith(“delete”)

|| method.getName().startsWith(“remove”)){

System.out.println(“切换到: master”);

DataSourceSwitcher.setMaster();

}

else  {

System.out.println(“切换到: slave”);

DataSourceSwitcher.setSlave();

}

}

// service方法执行完之后被调用

public void afterReturning(Object arg0, Method method, Object[] args, Object target) throws Throwable {

}

// 抛出Exception之后被调用

public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {

DataSourceSwitcher.setSlave();

System.out.println(“出现异常,切换到: slave”);

}

}



  1. import


    java.lang.reflect.Method;



  2. import


    org.springframework.aop.AfterReturningAdvice;



  3. import


    org.springframework.aop.MethodBeforeAdvice;



  4. import


    org.springframework.aop.ThrowsAdvice;




  5. import


    com.company.datasource.DataSourceSwitcher;




  6. public




    class


    DataSourceAdvice


    implements


    MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {



  7. // service方法执行之前被调用





  8. public




    void


    before(Method method, Object[] args, Object target)


    throws


    Throwable {


  9. System.out.println(

    “切入点: ”


    + target.getClass().getName() +


    “类中”


    + method.getName() +


    “方法”


    );



  10. if


    (method.getName().startsWith(


    “add”


    )


  11. || method.getName().startsWith(

    “create”


    )


  12. || method.getName().startsWith(

    “save”


    )


  13. || method.getName().startsWith(

    “edit”


    )


  14. || method.getName().startsWith(

    “update”


    )


  15. || method.getName().startsWith(

    “delete”


    )


  16. || method.getName().startsWith(

    “remove”


    )){


  17. System.out.println(

    “切换到: master”


    );


  18. DataSourceSwitcher.setMaster();

  19. }


  20. else


    {


  21. System.out.println(

    “切换到: slave”


    );


  22. DataSourceSwitcher.setSlave();

  23. }

  24. }



  25. // service方法执行完之后被调用





  26. public




    void


    afterReturning(Object arg0, Method method, Object[] args, Object target)


    throws


    Throwable {


  27. }



  28. // 抛出Exception之后被调用





  29. public




    void


    afterThrowing(Method method, Object[] args, Object target, Exception ex)


    throws


    Throwable {


  30. DataSourceSwitcher.setSlave();

  31. System.out.println(

    “出现异常,切换到: slave”


    );


  32. }


  33. }




数据源选择类 DataSourceSwitcher.java


Java代码

package com.company.datasource;

import org.springframework.util.Assert;

public class DataSourceSwitcher {

@SuppressWarnings(“rawtypes”)

private static final ThreadLocal contextHolder = new ThreadLocal();

@SuppressWarnings(“unchecked”)

public static void setDataSource(String dataSource) {

Assert.notNull(dataSource, “dataSource cannot be null”);

contextHolder.set(dataSource);

}

public static void setMaster(){

clearDataSource();

}

public static void setSlave() {

setDataSource(“slave”);

}

public static String getDataSource() {

return (String) contextHolder.get();

}

public static void clearDataSource() {

contextHolder.remove();

}

}



  1. package


    com.company.datasource;



  2. import


    org.springframework.util.Assert;




  3. public




    class


    DataSourceSwitcher {



  4. @SuppressWarnings


    (


    “rawtypes”


    )



  5. private




    static




    final


    ThreadLocal contextHolder =


    new


    ThreadLocal();




  6. @SuppressWarnings


    (


    “unchecked”


    )



  7. public




    static




    void


    setDataSource(String dataSource) {


  8. Assert.notNull(dataSource,

    “dataSource cannot be null”


    );


  9. contextHolder.set(dataSource);

  10. }



  11. public




    static




    void


    setMaster(){


  12. clearDataSource();

  13. }



  14. public




    static




    void


    setSlave() {


  15. setDataSource(

    “slave”


    );


  16. }



  17. public




    static


    String getDataSource() {



  18. return


    (String) contextHolder.get();


  19. }



  20. public




    static




    void


    clearDataSource() {


  21. contextHolder.remove();

  22. }

  23. }






DynamicDataSource.java数据源动态切换类


Java代码

package com.company.datasource;

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

public class DynamicDataSource extends AbstractRoutingDataSource {

@Override

protected Object determineCurrentLookupKey() {

return DataSourceSwitcher.getDataSource();

}

}



  1. package


    com.company.datasource;




  2. import


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




  3. public




    class


    DynamicDataSource


    extends


    AbstractRoutingDataSource {




  4. @Override





  5. protected


    Object determineCurrentLookupKey() {



  6. return


    DataSourceSwitcher.getDataSource();


  7. }


  8. }






下面配置spring applicationContext.xml文件


Xml代码

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans”

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:aop=”http://www.springframework.org/schema/aop”

xmlns:tx=”http://www.springframework.org/schema/tx” xmlns:context=”http://www.springframework.org/schema/context”

xsi:schemaLocation=”

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd”>

<context:annotation-config />

<!– 自动加载SERVICE DAO ACTION –>

<context:component-scan base-package=”cn.com.company.dao.*” />

<context:component-scan base-package=”cn.com.company.service.*” />

<context:component-scan base-package=”cn.com.company.action” />

<!– 加载properties配置文件 –>

<bean id=”propertyConfigurer”

class=”org.springframework.beans.factory.config.PropertyPlaceholderConfigurer”>

<property name=”locations”>

<list>

<value>classpath:jdbc.properties</value>

</list>

</property>

</bean>

<bean id=”parentDataSource” class=”com.mchange.v2.c3p0.ComboPooledDataSource”>

//***c3p0配置

</bean>

<!– 主数据源–>

<bean id=”masterDataSource” parent=”parentDataSource”>

<property name=”driverClass” value=”${master.jdbc.driverClassName}” />

<property name=”jdbcUrl” value=”${master.jdbc.url}” />

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

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

</bean>

<!– 从数据源–>

<bean id=”slaveDataSource” parent=”parentDataSource”>

<property name=”driverClass” value=”${slave.jdbc.driverClassName}” />

<property name=”jdbcUrl” value=”${slave.jdbc.url}” />

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

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

</bean>

<bean id=”dataSource” class=”com.company.datasource.DynamicDataSource”>

<property name=”targetDataSources”>

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

<entry key=”slave” value-ref=”slaveDataSource” />

</map>

</property>

<property name=”defaultTargetDataSource” ref=”masterDataSource” />

</bean>

<!– 配置sessionFactory –>

<bean id=”sessionFactory”

class=”org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean”>

<property name=”dataSource” ref=”dataSource”></property>

<property name=”packagesToScan” value=”cn.com.company.entity” />

<property name=”hibernateProperties”>

<props>

<prop>//***hibernate一些参数这里不写了</prop>

</props>

</property>

</bean>

<!– 切换数据源 –>

<bean id=”dataSourceAdvice” class=”com.company.aop.DataSourceAdvice” />

<aop:config>

<aop:advisor

pointcut=”execution(* cn.com.company.service..*Service.*(..))”

advice-ref=”dataSourceAdvice” />

</aop:config>

<!– 配置事务管理器 –>

<bean id=”transactionManager”

class=”org.springframework.orm.hibernate3.HibernateTransactionManager”>

<property name=”sessionFactory”>

<ref bean=”sessionFactory” />

</property>

</bean>

<!–配置事务的传播特性 –>

<tx:advice id=”txAdvice” transaction-manager=”transactionManager”>

<tx:attributes>

<!– 对增、删、改方法进行事务支持 –>

<tx:method name=”add*” propagation=”REQUIRED” />

<tx:method name=”create*” propagation=”REQUIRED” />

<tx:method name=”save*” propagation=”REQUIRED” />

<tx:method name=”edit*” propagation=”REQUIRED” />

<tx:method name=”update*” propagation=”REQUIRED” />

<tx:method name=”delete*” propagation=”REQUIRED” />

<tx:method name=”remove*” propagation=”REQUIRED” />

<!– 对查找方法进行只读事务 –>

<tx:method name=”loadByUsername*” propagation=”SUPPORTS” read-only=”true” />

<!– 对其它方法进行只读事务 –>

<tx:method name=”*” propagation=”SUPPORTS” read-only=”true” />

</tx:attributes>

</tx:advice>

<!–那些类的哪些方法参与事务 –>

<aop:config>

<aop:advisor

pointcut=”execution(* cn.com.company.service..*Service.*(..))”

advice-ref=”txAdvice” />

<aop:advisor

pointcut=”execution(* cn.com.company.service..*ServiceImpl.*(..))”

advice-ref=”txAdvice” />

</aop:config>

</beans>



  1. <?


    xml




    version


    =


    “1.0”




    encoding


    =


    “UTF-8”


    ?>





  2. <


    beans




    xmlns


    =


    “http://www.springframework.org/schema/beans”





  3. xmlns:xsi


    =


    “http://www.w3.org/2001/XMLSchema-instance”




    xmlns:aop


    =


    “http://www.springframework.org/schema/aop”





  4. xmlns:tx


    =


    “http://www.springframework.org/schema/tx”




    xmlns:context


    =


    “http://www.springframework.org/schema/context”





  5. xsi:schemaLocation


    =”


  6. http://www.springframework.org/schema/beans

  7. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

  8. http://www.springframework.org/schema/tx

  9. http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

  10. http://www.springframework.org/schema/aop

  11. http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

  12. http://www.springframework.org/schema/context

  13. http://www.springframework.org/schema/context/spring-context-3.0.xsd”

    >






  14. <


    context:annotation-config




    />





  15. <!– 自动加载SERVICE DAO ACTION –>





  16. <


    context:component-scan




    base-package


    =


    “cn.com.company.dao.*”




    />





  17. <


    context:component-scan




    base-package


    =


    “cn.com.company.service.*”




    />





  18. <


    context:component-scan




    base-package


    =


    “cn.com.company.action”




    />






  19. <!– 加载properties配置文件 –>





  20. <


    bean




    id


    =


    “propertyConfigurer”





  21. class


    =


    “org.springframework.beans.factory.config.PropertyPlaceholderConfigurer”


    >





  22. <


    property




    name


    =


    “locations”


    >





  23. <


    list


    >





  24. <


    value


    >


    classpath:jdbc.properties


    </


    value


    >





  25. </


    list


    >





  26. </


    property


    >





  27. </


    bean


    >






  28. <


    bean




    id


    =


    “parentDataSource”




    class


    =


    “com.mchange.v2.c3p0.ComboPooledDataSource”


    >




  29. //***c3p0配置


  30. </


    bean


    >





  31. <!– 主数据源–>





  32. <


    bean




    id


    =


    “masterDataSource”




    parent


    =


    “parentDataSource”


    >





  33. <


    property




    name


    =


    “driverClass”




    value


    =


    “${master.jdbc.driverClassName}”




    />





  34. <


    property




    name


    =


    “jdbcUrl”




    value


    =


    “${master.jdbc.url}”




    />





  35. <


    property




    name


    =


    “user”




    value


    =


    “${master.jdbc.username}”




    />





  36. <


    property




    name


    =


    “password”




    value


    =


    “${master.jdbc.password}”




    />





  37. </


    bean


    >





  38. <!– 从数据源–>





  39. <


    bean




    id


    =


    “slaveDataSource”




    parent


    =


    “parentDataSource”


    >





  40. <


    property




    name


    =


    “driverClass”




    value


    =


    “${slave.jdbc.driverClassName}”




    />





  41. <


    property




    name


    =


    “jdbcUrl”




    value


    =


    “${slave.jdbc.url}”




    />





  42. <


    property




    name


    =


    “user”




    value


    =


    “${slave.jdbc.username}”




    />





  43. <


    property




    name


    =


    “password”




    value


    =


    “${slave.jdbc.password}”




    />





  44. </


    bean


    >






  45. <


    bean




    id


    =


    “dataSource”




    class


    =


    “com.company.datasource.DynamicDataSource”


    >





  46. <


    property




    name


    =


    “targetDataSources”


    >





  47. <


    map




    key-type


    =


    “java.lang.String”


    >





  48. <


    entry




    key


    =


    “slave”




    value-ref


    =


    “slaveDataSource”




    />





  49. </


    map


    >





  50. </


    property


    >





  51. <


    property




    name


    =


    “defaultTargetDataSource”




    ref


    =


    “masterDataSource”




    />





  52. </


    bean


    >






  53. <!– 配置sessionFactory –>





  54. <


    bean




    id


    =


    “sessionFactory”





  55. class


    =


    “org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean”


    >





  56. <


    property




    name


    =


    “dataSource”




    ref


    =


    “dataSource”


    >


    </


    property


    >





  57. <


    property




    name


    =


    “packagesToScan”




    value


    =


    “cn.com.company.entity”




    />





  58. <


    property




    name


    =


    “hibernateProperties”


    >





  59. <


    props


    >






  60. <


    prop


    >


    //***hibernate一些参数这里不写了


    </


    prop


    >





  61. </


    props


    >





  62. </


    property


    >





  63. </


    bean


    >






  64. <!– 切换数据源 –>





  65. <


    bean




    id


    =


    “dataSourceAdvice”




    class


    =


    “com.company.aop.DataSourceAdvice”




    />





  66. <


    aop:config


    >





  67. <


    aop:advisor





  68. pointcut


    =


    “execution(* cn.com.company.service..*Service.*(..))”





  69. advice-ref


    =


    “dataSourceAdvice”




    />





  70. </


    aop:config


    >






  71. <!– 配置事务管理器 –>





  72. <


    bean




    id


    =


    “transactionManager”





  73. class


    =


    “org.springframework.orm.hibernate3.HibernateTransactionManager”


    >





  74. <


    property




    name


    =


    “sessionFactory”


    >





  75. <


    ref




    bean


    =


    “sessionFactory”




    />





  76. </


    property


    >





  77. </


    bean


    >





  78. <!–配置事务的传播特性 –>





  79. <


    tx:advice




    id


    =


    “txAdvice”




    transaction-manager


    =


    “transactionManager”


    >





  80. <


    tx:attributes


    >





  81. <!– 对增、删、改方法进行事务支持 –>





  82. <


    tx:method




    name


    =


    “add*”




    propagation


    =


    “REQUIRED”




    />





  83. <


    tx:method




    name


    =


    “create*”




    propagation


    =


    “REQUIRED”




    />





  84. <


    tx:method




    name


    =


    “save*”




    propagation


    =


    “REQUIRED”




    />





  85. <


    tx:method




    name


    =


    “edit*”




    propagation


    =


    “REQUIRED”




    />





  86. <


    tx:method




    name


    =


    “update*”




    propagation


    =


    “REQUIRED”




    />





  87. <


    tx:method




    name


    =


    “delete*”




    propagation


    =


    “REQUIRED”




    />





  88. <


    tx:method




    name


    =


    “remove*”




    propagation


    =


    “REQUIRED”




    />





  89. <!– 对查找方法进行只读事务 –>





  90. <


    tx:method




    name


    =


    “loadByUsername*”




    propagation


    =


    “SUPPORTS”




    read-only


    =


    “true”




    />





  91. <!– 对其它方法进行只读事务 –>





  92. <


    tx:method




    name


    =


    “*”




    propagation


    =


    “SUPPORTS”




    read-only


    =


    “true”




    />





  93. </


    tx:attributes


    >





  94. </


    tx:advice


    >





  95. <!–那些类的哪些方法参与事务 –>





  96. <


    aop:config


    >





  97. <


    aop:advisor





  98. pointcut


    =


    “execution(* cn.com.company.service..*Service.*(..))”





  99. advice-ref


    =


    “txAdvice”




    />





  100. <


    aop:advisor





  101. pointcut


    =


    “execution(* cn.com.company.service..*ServiceImpl.*(..))”





  102. advice-ref


    =


    “txAdvice”




    />





  103. </


    aop:config


    >







  104. </


    beans


    >








!注 applicationContenxt.xml中

<!– 切换数据源 –>

<bean id=”dataSourceAdvice” class=”com.company.aop.DataSourceAdvice” />

<aop:config>

<aop:advisor

pointcut=”execution(* cn.com.company.service..*Service.*(..))”

advice-ref=”dataSourceAdvice” />

</aop:config>

一定要配置在事务AOP之上