场景:在Spring+Mybatis搭建的项目中要配置两个数据库,如何实现?
其实也不是多难的事情,只要把配置配好了,一切问题就迎刃而解了,废话不多说,且看
如下配置……
配置一:jdbc.properties
配置两个数据库:myuser和myitem
1
2
3
4
5
6
7
8
9
|
myuser.jdbc.driver=com.mysql.jdbc.Driver
myuser.jdbc.url=jdbc:mysql:
//192.168.1.100:3306/myuser?useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
myuser.jdbc.username=root
myuser.jdbc.password=
123456
myitem.jdbc.driver=com.mysql.jdbc.Driver
myitem.jdbc.url=jdbc:mysql:
//192.168.1.100:3306/myitem?useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
myitem.jdbc.username=root
myitem.jdbc.password=
123456
|
配置二:applicationContext.xml
配置:
两个数据源(myUserDataSource和myItemDataSource)、
一个动态的DataSource(dynamicDataSource);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
<!-- 数据库连接池
1
:myuser-->
<bean id=
"myUserDataSource"
class
=
"com.jolbox.bonecp.BoneCPDataSource"
destroy-method=
"close"
>
<!-- 数据库驱动 -->
<property name=
"driverClass"
value=
"${myuser.jdbc.driver}"
/>
<!-- 相应驱动的jdbcUrl -->
<property name=
"jdbcUrl"
value=
"${myuser.jdbc.url}"
/>
<!-- 数据库的用户名 -->
<property name=
"username"
value=
"${myuser.jdbc.username}"
/>
<!-- 数据库的密码 -->
<property name=
"password"
value=
"${myuser.jdbc.password}"
/>
<!-- 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:
240
,如果要取消则设置为
0
-->
<property name=
"idleConnectionTestPeriod"
value=
"60"
/>
<!-- 连接池中未使用的链接最大存活时间,单位是分,默认值:
60
,如果要永远存活设置为
0
-->
<property name=
"idleMaxAge"
value=
"30"
/>
<!-- 每个分区最大的连接数 -->
<property name=
"maxConnectionsPerPartition"
value=
"150"
/>
<!-- 每个分区最小的连接数 -->
<property name=
"minConnectionsPerPartition"
value=
"5"
/>
</bean>
<!-- 数据库连接池
2
:myitem-->
<bean id=
"myItemDataSource"
class
=
"com.jolbox.bonecp.BoneCPDataSource"
destroy-method=
"close"
>
<!-- 数据库驱动 -->
<property name=
"driverClass"
value=
"${myitem.dbc.driver}"
/>
<!-- 相应驱动的jdbcUrl -->
<property name=
"jdbcUrl"
value=
"${myitem.jdbc.url}"
/>
<!-- 数据库的用户名 -->
<property name=
"username"
value=
"${myitem.jdbc.username}"
/>
<!-- 数据库的密码 -->
<property name=
"password"
value=
"${myitem.jdbc.password}"
/>
<!-- 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:
240
,如果要取消则设置为
0
-->
<property name=
"idleConnectionTestPeriod"
value=
"60"
/>
<!-- 连接池中未使用的链接最大存活时间,单位是分,默认值:
60
,如果要永远存活设置为
0
-->
<property name=
"idleMaxAge"
value=
"30"
/>
<!-- 每个分区最大的连接数 -->
<property name=
"maxConnectionsPerPartition"
value=
"150"
/>
<!-- 每个分区最小的连接数 -->
<property name=
"minConnectionsPerPartition"
value=
"5"
/>
</bean>
<!-- 数据库连接池 -->
<bean id=
"dynamicDataSource"
class
=
"com.simple.sso.dynamicdatasource.DynamicDataSource"
>
<property name=
"targetDataSources"
>
<map key-type=
"java.lang.String"
>
<entry value-ref=
"myUserDataSource"
key=
"userDataSource"
/>
<entry value-ref=
"myItemDataSource"
key=
"itemDataSource"
/>
</map>
</property>
<!-- 默认使用myUserDataSource的数据源,必须要配置,不然会启动报错 -->
<property name=
"defaultTargetDataSource"
ref=
"userDataSource"
/>
</bean>
|
有童鞋可能会问:DynamicDataSource这个类是怎么回事?
别急,这个类是自定义的一个类,此类必须继承:AbstractRoutingDataSource这个抽象类,并且重写
AbstractRoutingDataSource方法,动态数据源才会生效。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
/**
* 自定义动态数据源,继承AbstractRoutingDataSource抽象类,
* 重写determineCurrentLookupKey方法
* @author root
*/
public
class
DynamicDataSource
extends
AbstractRoutingDataSource {
@Override
protected
Object determineCurrentLookupKey() {
return
DataSourceContextHolder.getDbType();
}
}
|
问:DataSourceContextHolder这个类是什么干嘛的?
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
*设置数据库类型,指定使用哪个数据库
*@author root
*/
public
class
DataSourceContextHolder {
private
static
final
ThreadLocal<String> contextHolder =
new
ThreadLocal<String>();
//默认数据源(userDataSource)
public
static
final
String userDataSource =
"userDataSource"
;
//另外一个数据源(和配置文件中的key对应)
public
static
final
String itemDataSource =
"itemDataSource"
;
public
static
void
setDbType(String dbType) {
contextHolder.set(dbType);
}
public
static
String getDbType() {
return
((String) contextHolder.get());
}
public
static
void
clearDbType() {
contextHolder.remove();
}
}
|
问:那事物怎么管理呢?别急,继续往下看……
配置三:applicationContext-transaction.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<!-- 定义事务管理器 -->
<bean id=
"transactionManager"
class
=
"org.springframework.jdbc.datasource.DataSourceTransactionManager"
>
<property name=
"dataSource"
ref=
"dynamicDataSource"
/>
</bean>
<!-- 定义事务策略 -->
<tx:advice id=
"txAdvice"
transaction-manager=
"transactionManager"
>
<tx:attributes>
<!--所有以query开头的方法都是只读的 -->
<tx:method name=
"query*"
read-only=
"true"
/>
<!--其他方法使用默认事务策略 -->
<tx:method name=
"*"
/>
</tx:attributes>
</tx:advice>
<aop:config>
<!--pointcut元素定义一个切入点,execution中的第一个星号 用以匹配方法的返回类型,
这里星号表明匹配所有返回类型。 com.abc.dao.*.*(..)表明匹配com.simple.mybatis.service包下的所有类的所有
方法 -->
<aop:pointcut id=
"myPointcut"
expression=
"execution(* com.simple.sso.service.*.*(..))"
/>
<!--将定义好的事务处理策略应用到上述的切入点 -->
<aop:advisor advice-ref=
"txAdvice"
pointcut-ref=
"myPointcut"
/>
</aop:config>
|
问:那么sqlSessionFactory怎么获取数据源呢?继续配置……
配置四:applicationContext-mybatis.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<!-- 定义Mybatis的SqlSessionFactory -->
<bean id=
"sqlSessionFactory"
class
=
"org.mybatis.spring.SqlSessionFactoryBean"
>
<!-- 定义数据源 -->
<property name=
"dataSource"
ref=
"dynamicDataSource"
/>
<!-- 指定mybatis全局配置文件 -->
<property name=
"configLocation"
value=
"classpath:mybatis/mybatis-config.xml"
></property>
<!-- 扫描mappers目录以及子目录下的所有xml文件 -->
<!-- <property name=
"mapperLocations"
value=
"classpath:mybatis/mappers/**/*.xml"
/> -->
<!-- 别名扫描包 -->
<property name=
"typeAliasesPackage"
value=
"com.simple.sso.pojo"
/>
</bean>
|
到这里,其实该配置的都已经配置完了。
问:那么在代码中该如何使用呢?比如说要插入的数据时该往哪个数据库中插入呢?我怎么保证数据就是我要插入的数据库呢?
就是在代码中手动切换下,在事物开启之前先手动设置指定下数据库,然后进行逻辑,如果是要对配置的默认数据库进行操作的话就不用切数据库了,如果是对另外一个数据库操作的话就要在Controller中手动切换数据库:
1
2
3
4
5
6
7
|
//手动切换数据库
DataSourceContextHolder.setDbType(DataSourceContextHolder.itemDataSource);
// 需要执行的逻辑代码……对数据库的增删改
//这里要手动清理刚开启的事物,不然后面的操作可能会出现错误。
DataSourceContextHolder.clearDbType();
|
这样就欧了。
本文转自 兴趣e族 51CTO博客,原文链接:http://blog.51cto.com/simplelife/1706542