该示例是基于spring提供的AbstractRoutingDataSource,实现了一个动态数据源的功能,在spring配置中定义多个数据库分为主、从数据库,实现效果为当进行保存和修改记录时则对主表操作,查询则对从表进行操作,从而实现对数据库表的读写分离。这样做有利于提高网站的性能,特别是在数据库这一层。因为在实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的CPU较多,从而影响用户体验。我们通常的做法就是把查询从主库中抽取出来,采用多个从库,使用负载均衡,减轻每个从库的查询压力。该示例并未对数据库同步进行说明,只对读写操作的分离实现:
在进行操作之前,先简单说一下AbstractRoutingDataSource相关的东西:
1 AbstractRoutingDataSource继承了AbstractDataSource ,而AbstractDataSource 又是DataSource 的子类。DataSource 是javax.sql 的数据源接口,定义如下:2
3 public abstract class AbstractRoutingDataSource extends AbstractDataSource implementsInitializingBean {}4
5 public interface DataSource extendsCommonDataSource,Wrapper {6
7 /**
8 *
Attempts to establish a connection with the data source that9 * this DataSource
object represents.10 *11 *@returna connection to the data source12 *@exceptionSQLException if a database access error occurs13 */
14 Connection getConnection() throwsSQLException;15
16 /**
17 *
Attempts to establish a connection with the data source that18 * this DataSource
object represents.19 *20 *@paramusername the database user on whose behalf the connection is21 * being made22 *@parampassword the user‘s password23 *@returna connection to the data source24 *@exceptionSQLException if a database access error occurs25 *@since1.426 */
27 Connection getConnection(String username, String password)28 throwsSQLException;29
30 }31
32
33 public Connection getConnection() throwsSQLException {34 returndetermineTargetDataSource().getConnection();35 }36
37 public Connection getConnection(String username, String password) throwsSQLException {38 returndetermineTargetDataSource().getConnection(username, password);39 }40
41 protectedDataSource determineTargetDataSource() {42 Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");43 Object lookupKey =determineCurrentLookupKey();44 DataSource dataSource = this.resolvedDataSources.get(lookupKey);45 if (dataSource == null && (this.lenientFallback || lookupKey == null)) {46 dataSource = this.resolvedDefaultDataSource;47 }48 if (dataSource == null) {49 throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");50 }51 returndataSource;52 }
View Code
从上面的代码中不难看出,获取数据源首先是通过对determineCurrentLookupKey()的调用获取resolvedDataSources对应key的值,故执行创建一个动态数据源类继承AbstractRoutingDataSource,复写determineCurrentLookupKey()去自定义设置和获取resolvedDataSources的key就可以实现了
具体步骤如下:
第一步:
default-lazy-init="true">
class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
View Code
第二步:
1 public class DynamicDataSource extendsAbstractRoutingDataSource {2
3 @Override4 protectedObject determineCurrentLookupKey() {5
6 returnDynamicDataSourceHolder.getDataSouce();7 }8
9 }
创建动态数据源类继承AbstractRoutingDataSource
第三步:
1 public classDynamicDataSourceHolder {2 public static final ThreadLocal holder = new ThreadLocal();3
4 public static voidputDataSource(String name) {5 holder.set(name);6 }7
8 public staticString getDataSouce() {9 returnholder.get();10 }11 }
设置及获取每个线程访问的哪个数据源
第四步:
1 @Service("userService")2 @Transactional3 public class UserServiceImpl implementsUserService{4
5 @Autowired6 private UserMapper userDao;public voidadd(User user) {7
8 DynamicDataSourceHolder.putDataSource("masterdataSource");9 userDao.add(user);10 }11
12 public voidupdate(User user) {13
14 DynamicDataSourceHolder.putDataSource("masterdataSource");15 userDao.updates(user);16
17
18 }19
20 @Transactional(propagation =Propagation.NOT_SUPPORTED)21 public Listquery() {22
23 DynamicDataSourceHolder.putDataSource("slavedataSource");24 List user =userDao.query();25 returnuser;26
27 }28
29
30
31
32 }
对service实现层加入设置数据源代码
上述为实现读写分离的关键部分,只是为了简单的做一个示例,完成上面操作以后,可自行的对数据库进行新增和查询操作,查看效果
原文:http://www.cnblogs.com/HeQiangJava/p/7287740.html