实现读写分离的Web工程

前言

    本工程基于Spring提供的AbstractRoutingDataSource,实现了一个动态数据源的功能,即可以做到,当往数据库里面写数据时,则将数据写到一个数据库当中,一般称为写数据库;当要查询数据时,则获取另一个数据库中的信息,这个数据库一般称为读数据库。这样做,有利于提高网站的性能,特别是在数据库这一层。本工程就是实现了这样一个功能,当然对于写数据库如何跟读数据库如何同步的问题,这章不讲,下次文章再来解决。以下将关键代码附上。

相关配置文件

spring-beans.xml

xml version="1.0" encoding="UTF-8"?>
 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:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"
    default-lazy-init="true">

    
     base-package="com.tongtongxue">
         type="annotation" expression="org.springframework.stereotype.Controller" />
    

    
     location="classpath:jdbc.properties"/>

    
     id="dataSourceWrite" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
         name="driverClassName" value="${w.jdbc.driver}" />
         name="url" value="${w.jdbc.url}" />
         name="username" value="${w.jdbc.username}" />
         name="password" value="${w.jdbc.password}" />
         name="initialSize" value="${w.jdbc.initialSize}" />
         name="maxActive" value="${w.jdbc.maxActive}" />
         name="maxIdle" value="${w.jdbc.maxIdle}" />
         name="maxWait" value="${w.jdbc.maxWait}" />
    
    
    
     id="dataSourceRead" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
         name="driverClassName" value="${r.jdbc.driver}" />
         name="url" value="${r.jdbc.url}" />
         name="username" value="${r.jdbc.username}" />
         name="password" value="${r.jdbc.password}" />
         name="initialSize" value="${r.jdbc.initialSize}" />
         name="maxActive" value="${r.jdbc.maxActive}" />
         name="maxIdle" value="${r.jdbc.maxIdle}" />
         name="maxWait" value="${r.jdbc.maxWait}" />
    

     
    id="dynamicDataSource" class="com.tongtongxue.rw.DynamicDataSource">  
         
        name="targetDataSources">  
             
                value-ref="dataSourceWrite" key="dataSourceWrite">  
                value-ref="dataSourceRead" key="dataSourceRead">  
             
         
        name="defaultTargetDataSource" ref="dataSourceWrite" />      
   

    
     id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
         name="dataSource" ref="dynamicDataSource"/>
         name="typeAliasesPackage" value="com.tongtongxue.rw.model"/>
         name="mapperLocations" value="classpath:com/tongtongxue/rw/model/mapper/*Mapper.xml" />
    

    
     class="org.mybatis.spring.mapper.MapperScannerConfigurer">
         name="basePackage" value="com.tongtongxue"/>
         name="annotationClass" value="org.springframework.stereotype.Repository"/>
    

     id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         name="dataSource" ref="dataSourceWrite" />
    

    
     transaction-manager="transactionManager" />

    
     id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        
         name="maxUploadSize">
            20971520
        
         name="maxInMemorySize">
            4096
        
         name="defaultEncoding">
            UTF-8
        
    

动态数据源类DynamicDataSource

package com.tongtongxue.rw;

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

/**
 * 动态数据源
 * 
 * @author lzj
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

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

于设置及获取每个线程访问的哪个数据源

基于ThreadLocal来实现的。

package com.tongtongxue.rw;

import org.apache.commons.lang.StringUtils;

/**
 * 用于设置及获取每个线程访问的哪个数据源
 * 
 * @author lzj
 *
 */
public class DBHelper {

	private static ThreadLocal<String> dbContext = new ThreadLocal<String>();
	
	// 写数据源标识
	public final static String DB_WRITE = "dataSourceWrite";
	// 读数据源标识
	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);
	}
}

用户服务类

package com.tongtongxue.rw.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.tongtongxue.rw.DBHelper;
import com.tongtongxue.rw.dao.UserDao;
import com.tongtongxue.rw.model.User;
import com.tongtongxue.rw.service.IUserService;

/**
 * 用户服务类
 * 
 * @author lzj
 *
 */
@Service
@Transactional
public class UserService implements IUserService {
	
	@Autowired
	private UserDao userDao;

	@Override
	public void create(User user) throws RuntimeException {
		// 创建用户是写数据,则是将数据放到“写数据源”中
		DBHelper.setDbType(DBHelper.DB_WRITE);
		
		// 保存用户信息
		userDao.create(user);
	}

	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	@Override
	public List<User> queryForList() throws RuntimeException {
		// 查询用户数据,则是获取“读数据源”中的数据
		DBHelper.setDbType(DBHelper.DB_READ);
		return userDao.queryForList();
	}
}

你可能感兴趣的:(转)