Spring知识点梳理——读写分离

1、读写分离:可以通过Spring提供的AbstractRoutingDataSource类,重写determineCurrentLookupKey方法,实现动态切换数据源的功能;读写分离可以有效减轻写库的压力,又可以把查询数据的请求分发到不同读库;MySql主从同步传送门

2、写数据库:当调用insert、update、delete及一些实时数据用到的库;

3、读数据库:当调用select查询数据用到的库;

4、JaveWeb工程通过AbstractRoutingDataSource类实现读写分离;

5、jdbc.properties配置如下:

datasource.type=mysql
datasource.autoCommitOnClose=false
datasource.driverClassName=com.mysql.jdbc.Driver
#writer
w.datasource.url=jdbc:mysql://localhost:3306/zyfund?useUnicode=true&characterEncoding=UTF-8
w.datasource.username=root
w.datasource.password=123456
#reader
r.datasource.url=jdbc:mysql://192.168.37.128:3306/zyfund?useUnicode=true&characterEncoding=UTF-8
r.datasource.username=root
r.datasource.password=123456

6.application.xml文件:

 <!-- 引入配置文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
     
    <!--创建读的数据源 -->
    <bean id="dataSourceRead" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
      <property name="driverClassName" value="${datasource.driverClassName}"/>
      <property name="url" value="${r.datasource.url}"/>
      <property name="username" value="${r.datasource.username}"/>
      <property name="password" value="${r.datasource.password}"/>
      <property name="maxActive" value="${datasource.maxActive}"/>
      <property name="maxIdle" value="${datasource.maxIdle}"/>
      <property name="minIdle" value="${datasource.minIdle}"/>
    </bean>
    <!-- 创建写的数据库 -->
    <bean id="dataSourceWriter" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
      <property name="driverClassName" value="${datasource.driverClassName}"/>
      <property name="url" value="${w.datasource.url}"/>
      <property name="username" value="${w.datasource.username}"/>
      <property name="password" value="${w.datasource.password}"/>
      <property name="maxActive" value="${datasource.maxActive}"/>
      <property name="maxIdle" value="${datasource.maxIdle}"/>
      <property name="minIdle" value="${datasource.minIdle}"/>
    </bean>
    <!-- 动态数据源 -->  
    <bean id="dynamicDataSource" class="com.zyfund.admin.utils.aop.DynamicDataSource">  
       <!-- 通过key-value关联数据源 -->  
       <property name="targetDataSources">  
           <map>  
               <entry value-ref="dataSourceWriter" key="dataSourceWriter"></entry>  
               <entry value-ref="dataSourceRead" key="dataSourceRead"></entry>  
           </map>  
       </property>  
       <property name="defaultTargetDataSource" ref="dataSourceWriter" />      
    </bean>
   <!--  <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">  
        <property name="maxTotal"  value="${redis.pool.maxActive}"/>  
        <property name="maxIdle" value="${redis.pool.maxIdle}"/>  
        <property name="maxWaitMillis" value="${redis.pool.maxWait}"/>  
        <property name="testOnBorrow"  value="${redis.pool.testOnBorrow}"/>  
        <property name="testOnReturn" value="${redis.pool.testOnReturn}" />
    </bean>  
    <bean id="jedisShardInfo" class="redis.clients.jedis.JedisShardInfo">  
        <constructor-arg index="0" value="${redis.ip}"/>  
        <constructor-arg index="1" value="${redis.port}" type="int"/>  
    </bean>  
      
    <bean id="jedisPool" class="redis.clients.jedis.ShardedJedisPool">  
        <constructor-arg index="0" ref="jedisPoolConfig" />  
        <constructor-arg index="1">  
            <list>  
                <ref bean="jedisShardInfo" />  
            </list>  
        </constructor-arg>  
    </bean>  -->
     
    <!-- 配置SqlSessionFactoryBean -->
    <bean id="sqlSessionFactory" class="com.zyfund.admin.utils.BaseSqlSessionFactoryBean">
        <!-- 通过动态数据源获取sqlSessionFactory对象 -->
        <property name="dataSource" ref="dynamicDataSource"/>
        <property name="configLocation" value="classpath:mybatis.xml"/>
        <property name="mapperLocations" value="classpath*:com/**/*Mapper.xml"/>
    </bean>
     <!-- 定义日志处理类 -->
         <bean id="logAdvice" class="com.zyfund.admin.utils.aop.LogAdvice" />
    <!-- 配置事务管理器 -->
        <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dynamicDataSource" />
        </bean>
        
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="do*" propagation="REQUIRED" />
                <tx:method name="delete*" propagation="REQUIRED" />
                <tx:method name="merge*" propagation="REQUIRED" />
                <tx:method name="add*" propagation="REQUIRED" />
                <tx:method name="update*" propagation="REQUIRED" />
                <tx:method name="enable*" propagation="REQUIRED" />
                <tx:method name="sync*" propagation="REQUIRED" />
                <!-- <tx:method name="*" read-only="true"/>  --> 
                <!-- <tx:method name="add*" rollback-for="Throwable"/> --><!-- 在add开头的方法中遇到异常(Throwable)就回滚-->
            </tx:attributes>
        </tx:advice>
        
        <aop:config >
            <aop:pointcut expression="execution (* com.zyfund.admin.service..*.*(..))" id="services" />
            <aop:advisor advice-ref="txAdvice" pointcut-ref="services" />
        </aop:config> 

7、编写动态数据源处理类(dynamicDataSource

package com.zyfund.admin.utils.aop;

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

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        Object obj = DBHelper.getDbType();
        return obj;
    }

}
 

):

8、编写DBHelper帮助类(数据源切换类):

package com.zyfund.admin.utils.aop;
import org.apache.commons.lang.StringUtils;
/****
 * 动态切换数据源的帮助类
 * @author Administrator
 *
 */
public class DBHelper {
    private static ThreadLocal<String> dbContext = new ThreadLocal<String>();

    // 写数据源标识
    public final static String DB_WRITE = "dataSourceWriter";
    // 读数据源标识
    public final static String DB_READ = "dataSourceRead";

    /**
     * 获取数据源类型,即是写数据源,还是读数据源
     * 
     * @return
     */
    public static String getDbType() {
        String db_type = dbContext.get();
        if (StringUtils.isEmpty(db_type)) {
            // 默认是写数据源
            db_type = DB_WRITE;
        }
        return db_type;
    }

    /**
     * 设置该线程的数据源类型
     * 
     * @param str
     */
    public static void setDbType(String str) {
        dbContext.set(str);
    }
}

9.service实现类切换数据源:

/*@Aspect 此注解会影响数据源切换,运行代码得知不加的话会先执行DynamicDataSource里的determineCurrentLookupKey方法,后执行Service层里DBHelper.setDbType()方法,导致数据源切换失败!
*/
@Aspect
@Service
public class UserManageServiceImpl implements UserManageService{
    private static Logger log = Logger.getLogger(UserManageServiceImpl.class);
    @Autowired
    private UserManageDao userManageDao;
 
    public UserManage login(String loginName, String password) {
        DBHelper.setDbType(DBHelper.DB_READ);
        return userManageDao.login(loginName, password);
    }
 
 
 
    public boolean exists(String username) {
        DBHelper.setDbType(DBHelper.DB_READ);
        UserManage user = userManageDao.exists(username);
        return user!=null?true:false;
    }
 
    public boolean add(UserManage user) {
        DBHelper.setDbType(DBHelper.DB_WRITE);
        user.setCreateat(new Date());
        return userManageDao.add(user);
    }
 
    public boolean updatePwd(String username,String password) {
        DBHelper.setDbType(DBHelper.DB_WRITE);
        return userManageDao.updatePwd(username,password);
    }
 
    public UserManage getById(String id) {
        DBHelper.setDbType(DBHelper.DB_READ);
        return userManageDao.getById(Integer.parseInt(id));
    
    }
 
    public boolean update(UserManage user) {
        DBHelper.setDbType(DBHelper.DB_WRITE);
        return userManageDao.update(user);
    }
 
    public boolean delete(String id) {
        DBHelper.setDbType(DBHelper.DB_WRITE);
        return userManageDao.delete(Integer.parseInt(id));
    }
 
    public List<UserManageVo> getAllList(Integer page, String search,String phone) {
        DBHelper.setDbType(DBHelper.DB_READ);
        Integer pageSize = 20;
        log.info("start:"+page*pageSize+";page:"+page);
        if(search==null){
            search = "";
        }
        List<UserManageVo> list =new ArrayList<UserManageVo>();
        List<UserManage> userManages = userManageDao.getSearchList(page*pageSize, pageSize,search,phone);
        for(UserManage userManage :userManages){
            UserManageVo vo =new UserManageVo();
            BeanUtils.copyProperties(userManage, vo);
            list.add(vo);
        }
        return list;
    }
 
    public Integer getSearchListCount(String search,String phone) {
        // TODO 自动生成的方法存根
        DBHelper.setDbType(DBHelper.DB_READ);
        return userManageDao.getSearchListCount(search,phone);
    }


}
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值