spring+hibernate应用层读写分离

来源:互联网 发布:linux怎么建站 编辑:程序博客网 时间:2024/05/22 07:00

spring+hibernate应用层读写分离方案,是基于AbstractRoutingDataSource和AOP实现的。其中AbstractRoutingDataSource用于管理数据源并且根据key返回相应的数据源,AOP决定了什么时候使用什么数据源的key。

1、相关类的代码实现:
1)DataSource 注解类,用来标注某个方法使用的数据源,不标注则使用默认的

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface DataSource {    /**     * key="read" 读库(从),key="write" 写库(主)     * @return     */    public String key();}

2)DynamicDataSource 类重写determineCurrentLookupKey方法,返回数据源的key

public class DynamicDataSource extends AbstractRoutingDataSource {    @Override    protected Object determineCurrentLookupKey() {        return DynamicDataSourceHolder.getDataSource();    }}

3)DynamicDataSourceHolder 类用于线程安全的保存数据源的key

public class DynamicDataSourceHolder {    private static final ThreadLocal<String> dataSourceHolder = new ThreadLocal<>();    public static void setDataSource(String dataSourceKey) {        dataSourceHolder.set(dataSourceKey);    }    public static String getDataSource() {        return dataSourceHolder.get();    }    public static void clearDataSource() {        dataSourceHolder.remove();    }}

4)DynamicDataSourceAop ,设置拦截的方法层面,下面是拦截在service层,当该service执行之前,通过判断方法有没有DataSource注解,有则根据DataSource中的key设置数据源的key;service方法执行完毕清除数据源key的设置。
service层使用DataSource注解的原则是:当service里面有写方法时就不需要设置,默认使用写库,此时读写方法都在写库中完成;当service里面没有写方法时就使用DataSource设置读库,读方法在读库中完成。

@Component@Aspect@EnableAspectJAutoProxy(proxyTargetClass = true)public class DynamicDataSourceAop {    /**     * service层方法执行前选择数据源     * @param point     */    @Before("execution(* com.test.service..*.*(..))")    public void before(JoinPoint point) {        Object target = point.getTarget();        String methodName = point.getSignature().getName();        Class clazz = target.getClass();        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();        try {            Method method = clazz.getMethod(methodName, parameterTypes);            if (method != null && method.isAnnotationPresent(DataSource.class)) {                DataSource data = method.getAnnotation(DataSource.class);                DynamicDataSourceHolder.setDataSource(data.key());            }        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * service层方法执行完后清空数据源选择,当找不到相应的key的数据源会使用默认的数据源     * @param point     */    @After("execution(* com.test.service..*.*(..))")    public void after(JoinPoint point) {        DynamicDataSourceHolder.clearDataSource();    }}

2、spring配置文件

    <bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">        <property name="url" value="${masterconnection.url}" />        <property name="username" value="${masterconnection.username}" />        <property name="password" value="${masterconnection.password}" />    </bean>    <bean id="slaveDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">        <property name="url" value="${slaveconnection.url}" />        <property name="username" value="${slaveconnection.username}" />        <property name="password" value="${slaveconnection.password}" />    </bean>    <!-- 自定义动态数据源 -->    <bean id="dataSource" class="com.test.dao.datasource.DynamicDataSource">        <property name="targetDataSources">            <map key-type="java.lang.String">                <!-- 配置读写数据源 -->                <entry value-ref="masterDataSource" key="write"></entry>                <entry value-ref="slaveDataSource" key="read"></entry>            </map>        </property>        <property name="defaultTargetDataSource" ref="masterDataSource"></property>    </bean>    <!-- classpath是指 WEB-INF文件夹下的classes目录, classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找  -->    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >        <property name="dataSource" ref="dataSource"/>        <property name="mappingLocations" value="classpath:com/test/dao/hbm/*.hbm.xml"/>        <property name="hibernateProperties">            <props>                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>                <prop key="hibernate.show_sql">false</prop>                <prop key="hibernate.format_sql">true</prop>            </props>        </property>    </bean>    <!-- 开启注解事务 只对当前配置文件有效 -->    <tx:annotation-driven transaction-manager="txManager"/>    <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory"/>    </bean>
原创粉丝点击