场景:在Spring+Mybatis搭建的项目中要配置两个数据库,如何实现?
其实也不是多难的事情,只要把配置配好了,一切问题就迎刃而解了,废话不多说,且看
如下配置……
配置一:jdbc.properties
配置两个数据库:myuser和myitem
myuser.jdbc.driver=com.mysql.jdbc.Drivermyuser.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 :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方法,动态数据源才会生效。
代码如下:
/** * 自定义动态数据源,继承AbstractRoutingDataSource抽象类, * 重写determineCurrentLookupKey方法 * @author root */public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDbType(); }}
问:DataSourceContextHolder这个类是什么干嘛的?
代码如下:
/***设置数据库类型,指定使用哪个数据库*@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
<!-- 定义事务管理器 --> <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
<!-- 定义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中手动切换数据库:
//手动切换数据库DataSourceContextHolder.setDbType(DataSourceContextHolder.itemDataSource);// 需要执行的逻辑代码……对数据库的增删改//这里要手动清理刚开启的事物,不然后面的操作可能会出现错误。DataSourceContextHolder.clearDbType();
这样就欧了。
本文出自 “SimpleLife” 博客,请务必保留此出处http://simplelife.blog.51cto.com/9954761/1706542