zoukankan      html  css  js  c++  java
  • 分库设计

    <!-- 数据源(主库) -->                        
            <bean id="dataSource_main" class="com.mchange.v2.c3p0.ComboPooledDataSource">
                <property name="driverClass" value="${jdbc.driverclass}" />
                <property name="jdbcUrl" value="${jdbc.url}" />
                <property name="user" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
                
                <property name="maxPoolSize" value="${c3p0.pool.size.max}" />
                <property name="minPoolSize" value="${c3p0.pool.size.min}" />
                <property name="initialPoolSize" value="${c3p0.pool.size.ini}" />
                <property name="acquireIncrement" value="${c3p0.pool.size.increment}" />
            </bean>
            
            <!-- 数据源(从库) -->                        
            <bean id="dataSource_1" parent="dataSource_main">
                <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/lsn_surveypark0909_1" />
            </bean>
            
            
            <!-- 数据源路由器 -->
            <bean id="dataSource_router" class="cn.itcast.surveypark.datasource.SurveyparkDataSourceRouter">
                <property name="targetDataSources">
                    <map>
                        <entry key="odd" value-ref="dataSource_main" />
                        <entry key="even" value-ref="dataSource_1" />
                    </map>
                </property>
                <property name="defaultTargetDataSource" ref="dataSource_main" />
            </bean>
        <!-- aop事务配置 -->
            <aop:config>
                <!-- 事务切入点 -->
                <aop:pointcut expression="execution(* *..*Service.*(..))" id="txPointcut"/>
                <!-- 日志切入点 -->
                <aop:pointcut expression="(execution(* *..*Service.save*(..))
                                        or execution(* *..*Service.update*(..))
                                        or execution(* *..*Service.delete*(..))
                                        or execution(* *..*Service.batch*(..))
                                        or execution(* *..*Service.new*(..))) and !bean(logService)" 
                            id="loggerPointcut"/>
                
                <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" order="1"/>
                
                <!-- 配置日志切面 -->
                <aop:aspect id="loggerAspect" ref="logger" order="0">
                    <aop:around method="record" pointcut-ref="loggerPointcut"/>
                </aop:aspect>
            </aop:config>
    aop
    /**
     * 调查令牌,绑定到当前的线程,传播到数据源路由器.进行分库判断
     */
    public class SurveyToken {
        
        private Survey currentSurvey ;
        
        private static ThreadLocal<SurveyToken> t = new ThreadLocal<SurveyToken>();
        
        public Survey getCurrentSurvey() {
            return currentSurvey;
        }
    
        public void setCurrentSurvey(Survey currentSurvey) {
            this.currentSurvey = currentSurvey;
        }
    
        /**
         * 将令牌对象绑定到当前线程
         */
        public static void bindingToken(SurveyToken token){
            t.set(token);
        }
        
        /**
         * 从当前线程取得绑定的令牌对象
         */
        public static SurveyToken getCurrentToken(){
            return t.get() ;
        }
        
        /**
         * 解除令牌的绑定
         */
        public static void unbindToken(){
            t.remove() ;
        }
    }
    token

    主要思想是自定义一个方法继承AbstractRoutingDataSource,在保存答案方法前绑定令牌到当前线程,然后用debug模式看在哪里会调用数据路由器,需等答案保存完毕立刻

    解除令牌的绑定,然后log保存就不会受影响(因为从库没有log表)。所以要注意2个切面配置顺序,可以看图

    特别注意: 由于分库会有并发情况,需要把令牌的绑定到当前线程,然后取也是在同一个线程取。

        //绑定令牌到当前线程
                SurveyToken token = new SurveyToken();
                token.setCurrentSurvey(getCurrentSurvey());
                SurveyToken.bindingToken(token);
                
                //TODO 答案入库
                surveyService.saveAnswers(processAnswers());
    View Code
    /**
     * 自定义数据源路由器,根据id来判断是保存在哪个库中,实际工作中情况肯定比这复杂。
     */
    public class SurveyparkDataSourceRouter extends AbstractRoutingDataSource {
    
        protected Object determineCurrentLookupKey() {
            SurveyToken token = SurveyToken.getCurrentToken();
            if(token != null){
                int id = token.getCurrentSurvey().getId();
                //解除绑定
                SurveyToken.unbindToken();
                return (id % 2) == 0?"even":"odd" ;
            }
            return null;
        }
    }
  • 相关阅读:
    动态规划>0/1背包问题 小强斋
    【C/C++和指针】auto_ptr智能指针
    WEBSHELL
    sql反模式分析1
    SQLServer之Compute/ComputeBy实现数据汇总
    链表算法大全
    【C++ Primer】自己动手编写函数 atoi(char *str)
    MySQL 5.5 的COMPRESSED INNODB 表
    【设计模式】加薪非要老总批 职责链模式
    【C和指针】const指针
  • 原文地址:https://www.cnblogs.com/skyislimit/p/6486848.html
Copyright © 2011-2022 走看看