持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
一个ssm项目中需要扩展多个数据源,原来只有一个mysql,现在需要再扩展一个mysql,现将需要改动的地方做一个记录。
db.properties修改
首先,需要在数据源配置文件中增加新数据源配置。因为都是mysql,除了需要改动的,其他配置都是用了一样的参数,如果需要更改,可以自行增加配置参数。
代码语言:javascript复制# 数据源1
jdbc.user=root
jdbc.password=root
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/db1?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
# 数据源2
jdbc2.jdbcUrl=jdbc:mysql://localhost:3306/db1?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
jdbc2.user=root
jdbc2.password=root
# 公用配置
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.initPoolSize=5
jdbc.maxPoolSize=1024
spring.xml修改
spring.xml中需要新增数据源配置,以及多源数据库如何选择的配置。
代码语言:javascript复制
<!-- 导入资源文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- db1数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
<!-- db2数据库-->
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc2.user}"></property>
<property name="password" value="${jdbc2.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc2.jdbcUrl}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
<!-- 动态选择数据源,指向com.demo.test.dataSource.DynamicDataSource,后文会贴出代码 -->
<bean id="dynamicDataSource" class="com.demo.test.dataSource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="defaultDB" value-ref="dataSource"/>
<entry key="DataDB" value-ref="dataSource2"/>
</map>
</property>
<!--默认数据源-->
<property name="defaultTargetDataSource" ref="dataSource2"/>
</bean>
<!-- 配置 SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- 更改指向 dynamicDataSource -->
<property name="dataSource" ref="dynamicDataSource"></property>
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
</bean>
增加数据源切换类
数据源枚举类
代码语言:javascript复制public enum DataSourceEnum {
DS1("defaultDB"), DS2("DataDB");
private String key;
DataSourceEnum(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
线程持有数据源标识类
用于标记线程使用哪个数据源标识
代码语言:javascript复制public class DataSourceHolder {
private static final ThreadLocal<String> dataSources = new ThreadLocal<String>();
public static void setDataSources(String dataSource) {
dataSources.set(dataSource);
}
public static String getDataSources() {
return dataSources.get();
}
}
配置动态数据源类
AbstractRoutingDataSource 类:可以根据用户定义的规则选择当前的数据源,多源数据库需要使用该类实现多源数据库选择。
在每次数据库查询操作前执行,determineCurrentLookupKey() 决定使用哪个数据源。
实现的具体逻辑:继承 AbstractRoutingDataSource 类并重写 determineCurrentLookupKey 方法。把配置的多个数据源会放在AbstractRoutingDataSource的 targetDataSources和defaultTargetDataSource中,然后通过afterPropertiesSet()方法将数据源分别进行复制到resolvedDataSources和resolvedDefaultDataSource中。调用AbstractRoutingDataSource的getConnection()的方法的时候,先调用determineTargetDataSource()方法返回DataSource在进行getConnection()。
代码语言:javascript复制public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSources();
}
}
切换数据源代码
配置完上诉代码,到此可以在查询数据源时增加一个选择数据源语句实现选择数据源。例如:
代码语言:javascript复制 public User test01(String username) {
DataSourceHolder.setDataSources(DataSourceEnum.DS1.getKey());
return userDao.findUserByName(username);
}
public User test02(String username) {
DataSourceHolder.setDataSources(DataSourceEnum.DS2.getKey());
return userDao.findUserByName(username);
}
自动切换数据源
手动切换数据源需要每个方法都需要进行修改,太过于麻烦。
这里可以利用aop,实现根据包名自动切换数据源。
切面类
db1数据源都在db1包名下,db2数据源都在db2数据源下。如果你的项目文件结构不适用,可以根据能区分开数据源的策略进行自动切换,这个策略需要你自己去想了