Spring AbstractRoutingDataSource实现读写分离的Web工程

来源:互联网 发布:淘宝商品迁徙 编辑:程序博客网 时间:2024/06/07 15:27

前言

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

相关配置文件

spring-beans.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: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">    <!-- 自动扫描与装配bean -->    <context:component-scan base-package="com.tongtongxue">        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />    </context:component-scan>    <!-- 数据源连接配置文件 -->    <context:property-placeholder location="classpath:jdbc.properties"/>    <!-- 写数据源配置 -->    <bean id="dataSourceWrite" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">        <property name="driverClassName" value="${w.jdbc.driver}" />        <property name="url" value="${w.jdbc.url}" />        <property name="username" value="${w.jdbc.username}" />        <property name="password" value="${w.jdbc.password}" />        <property name="initialSize" value="${w.jdbc.initialSize}" />        <property name="maxActive" value="${w.jdbc.maxActive}" />        <property name="maxIdle" value="${w.jdbc.maxIdle}" />        <property name="maxWait" value="${w.jdbc.maxWait}" />    </bean>        <!-- 读数据源配置 -->    <bean id="dataSourceRead" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">        <property name="driverClassName" value="${r.jdbc.driver}" />        <property name="url" value="${r.jdbc.url}" />        <property name="username" value="${r.jdbc.username}" />        <property name="password" value="${r.jdbc.password}" />        <property name="initialSize" value="${r.jdbc.initialSize}" />        <property name="maxActive" value="${r.jdbc.maxActive}" />        <property name="maxIdle" value="${r.jdbc.maxIdle}" />        <property name="maxWait" value="${r.jdbc.maxWait}" />    </bean>   <!-- 动态数据源 -->     <bean id="dynamicDataSource" class="com.tongtongxue.rw.DynamicDataSource">         <!-- 通过key-value关联数据源 -->         <property name="targetDataSources">             <map>                 <entry value-ref="dataSourceWrite" key="dataSourceWrite"></entry>                 <entry value-ref="dataSourceRead" key="dataSourceRead"></entry>             </map>         </property>         <property name="defaultTargetDataSource" ref="dataSourceWrite" />         </bean>    <!-- spring和mybatis整合,不需要mybatis的配置映射文件 -->    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">        <property name="dataSource" ref="dynamicDataSource"/>        <property name="typeAliasesPackage" value="com.tongtongxue.rw.model"/>        <property name="mapperLocations" value="classpath:com/tongtongxue/rw/model/mapper/*Mapper.xml" />    </bean>    <!-- 扫描basePackage下所有以@Repository标识的 接口进行自动生成代理的Dao -->    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">        <property name="basePackage" value="com.tongtongxue"/>        <property name="annotationClass" value="org.springframework.stereotype.Repository"/>    </bean>    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSourceWrite" />    </bean>    <!-- 注解式事务管理,需要在Service类上标注@Transactional -->    <tx:annotation-driven transaction-manager="transactionManager" />    <!-- 处理包含文件上传的MultipartRequest -->    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">        <!-- 单位:字节, 1048576=1M,5242880=5M,10485760=10M,20971520=20M,52428800=50M  -->        <property name="maxUploadSize">            <value>20971520</value>        </property>        <property name="maxInMemorySize">            <value>4096</value>        </property>        <property name="defaultEncoding">            <value>UTF-8</value>        </property>    </bean></beans>

动态数据源类DynamicDataSource

package com.tongtongxue.rw;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * 动态数据源 *  * @author lzj * */public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected 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@Transactionalpublic class UserService implements IUserService {@Autowiredprivate UserDao userDao;@Overridepublic void create(User user) throws RuntimeException {// 创建用户是写数据,则是将数据放到“写数据源”中DBHelper.setDbType(DBHelper.DB_WRITE);// 保存用户信息userDao.create(user);}@Transactional(propagation = Propagation.NOT_SUPPORTED)@Overridepublic List<User> queryForList() throws RuntimeException {// 查询用户数据,则是获取“读数据源”中的数据DBHelper.setDbType(DBHelper.DB_READ);return userDao.queryForList();}}
原创粉丝点击