SpringMVC+Mybatis 多数据源配置
2017-12-01 15:10
393 查看
浪费了一上午的时间,参考了各种大神的帖子,并不好用。有的是能用,但不支持事务,有的压根因为配置习惯的不同或者spring版本不一样,配置也不能用,这里粘贴下我自己的配置,希望能帮你找到一些思路,如果能直接集成成功,那是最好啦
废话不多说,直接上代码。
1、项目为Spring-SpringMVC-Mybatis maven
2、SpringMVC 版本 4.3
3、开发工具 IDEA
4、数据库连接池用的阿里 druid
主要修改以下配置:
- jdbc.properties
- springMvcContext-base.xml
- 增加相关代码块
1、修改jdbc.properties
2、修改springMvcContext-base.xml
(只有核心配置,其他的不贴了)
3、增加相关代码块
注:利用注解实现动态切换相关数据源
DynamicDataSource.class
DynamicDataSourceHolder.class
DataSourceAspect.class
DataSource.class
调用方法
在如果你的事务控制在service层,建议在controller下调用 添加如下代码块(支持在类和方法级调用)
关于一些疑问:
动态切换数据源以后,需要再切换回来吗?答案:不需要,因为之前已经设置默认的数据源,只有添加注解DataSource的地方,才能改变数据源,如果其他类或者方法没有添加此注解DataSource,将用默认数据源执行数据库操作。
所以,建议在项目初始就将访问不同数据源的controller 或者业务进行分包管理,防止代码混乱
废话不多说,直接上代码。
1、项目为Spring-SpringMVC-Mybatis maven
2、SpringMVC 版本 4.3
3、开发工具 IDEA
4、数据库连接池用的阿里 druid
主要修改以下配置:
- jdbc.properties
- springMvcContext-base.xml
- 增加相关代码块
1、修改jdbc.properties
driver=com.microsoft.sqlserver.jdbc.SQLServerDriver url=jdbc:sqlserver://192.168.0.188:1433;databaseName=xxxxxxx username=sa password=sa validationQuery:select 1 driver_two=oracle.jdbc.driver.OracleDriver url_two=jdbc:oracle:thin:@192.168.0.188:1521:ORCL username_two=sa password_two=sa validationQuery_two:select 1 from dual filters:stat maxActive:20 initialSize:1 maxWait:60000 minIdle:10 maxIdle:15 timeBetweenEvictionRunsMillis:60000 minEvictableIdleTimeMillis:300000 testWhileIdle:true testOnBorrow:false testOnReturn:false maxOpenPreparedStatements:20 removeAbandoned:true removeAbandonedTimeout:1800 logAbandoned:true
2、修改springMvcContext-base.xml
(只有核心配置,其他的不贴了)
<!-- 配置数据源_2:阿里 druid数据库连接池 --> <bean id="dataSource_sqlserver" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <!-- 数据库基本信息配置 --> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> <property name="driverClassName" value="${driver}" /> <property name="filters" value="${filters}" /> <!-- 最大并发连接数 --> <property name="maxActive" value="${maxActive}" /> <!-- 初始化连接数量 --> <property name="initialSize" value="${initialSize}" /> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="${maxWait}" /> <!-- 最小空闲连接数 --> <property name="minIdle" value="${minIdle}" /> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" /> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" /> <property name="validationQuery" value="${validationQuery}" /> <property name="testWhileIdle" value="${testWhileIdle}" /> <property name="testOnBorrow" value="${testOnBorrow}" /> <property name="testOnReturn" value="${testOnReturn}" /> <property name="maxOpenPreparedStatements" value="${maxOpenPreparedStatements}" /> <!-- 打开removeAbandoned功能 --> <property name="removeAbandoned" value="${removeAbandoned}" /> <!-- 1800秒,也就是30分钟 --> <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> <!-- 关闭abanded连接时输出错误日志 --> <property name="logAbandoned" value="${logAbandoned}" /> </bean> <bean id="dataSource_oracle" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <!-- 数据库基本信息配置 --> <property name="url" value="${url_two}" /> <property name="username" value="${username_two}" /> <property name="password" value="${password_two}" /> <property name="driverClassName" value="${driver_two}" /> <property name="filters" value="${filters}" /> <!-- 最大并发连接数 --> <property name="maxActive" value="${maxActive}" /> <!-- 初始化连接数量 --> <property name="initialSize" value="${initialSize}" /> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="${maxWait}" /> <!-- 最小空闲连接数 --> <property name="minIdle" value="${minIdle}" /> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" /> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" /> <property name="validationQuery" value="${validationQuery_two}" /> <property name="testWhileIdle" value="${testWhileIdle}" /> <property name="testOnBorrow" value="${testOnBorrow}" /> <property name="testOnReturn" value="${testOnReturn}" /> <property name="maxOpenPreparedStatements" value="${maxOpenPreparedStatements}" /> <!-- 打开removeAbandoned功能 --> <property name="removeAbandoned" value="${removeAbandoned}" /> <!-- 1800秒,也就是30分钟 --> <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> <!-- 关闭abanded连接时输出错误日志 --> <property name="logAbandoned" value="${logAbandoned}" /> </bean> 关键在此 ---------- <!--双数据源--> <bean id="dataSource" class="com.googosoft.util.double_datasource.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry value-ref="dataSource_sqlserver" key="dataSource_sqlserver"></entry><!--数据源的名字--> <entry value-ref="dataSource_oracle" key="dataSource_oracle"></entry> </map><!--数据源的名字--> </property> </bean> <!-- 配置数据库注解aop --> <bean id="dataSourceAspect" class="com.alibaba.util.double_datasource.DataSourceAspect"/> <!-- 使用aop技术实现事物处理 --> <aop:config> <!-- id:事务切入点名称 expression:事务切入点正则表达式 --> <aop:pointcut id="serviceMethods" expression="execution(* com.alibaba.serviceImpl..*.*(..))" /> <!-- expression="execution(* com.alibaba.serviceImpl.*.*(..))" /> --> <!-- pointcut-ref:事务切入点名称 advice-ref:事务通知名称 --> <!--数据源选择切面,保证在事务开始之前执行--> <aop:advisor pointcut-ref="serviceMethods" advice-ref="dataSourceAspect" order="1" /><!--数据源切面执行顺序--> <aop:advisor pointcut-ref="serviceMethods" advice-ref="txAdvice" order="2" /><!--数据源的名字--> </aop:config> ---------- <!-- 配置Session工厂 --> <!-- spring和MyBatis整合--> <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 指明mybatis主配置文件路径 --> <property name="configLocation" value="classpath:mybatis.cfg.xml"></property> <!-- 指明mybatis的映射位置 自动扫描需要定义类别名的包,将包内的JAVA类的类名作为类别名--> <property name="mapperLocations"> <list> <value>classpath:orm/**/*.xml</value> </list> </property> </bean> <!-- DAO接口所在包名,Spring会自动查找其下的类 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.alibaba.mapper" /> <property name="sqlSessionFactoryBeanName" value="sessionFactory"></property> </bean> <!-- 配置SqlSession模版类--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype"> <constructor-arg ref="sessionFactory"></constructor-arg> </bean> <!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务通知 id:事务通知名称,transaction-manager:指定事务管理器名称 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 以delete、insert、update、sava、do、go开头的所有方法采用只读型事务控制类型 --> <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" /> <tx:method name="do*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" timeout="10" /> <tx:method name="go*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" timeout="10" /> <!-- 以load、find、search、select、get开头的所有方法采用只读型事务控制类型 --> <tx:method name="load*" propagation="SUPPORTS" read-only="true"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true"/> <tx:method name="search*" propagation="SUPPORTS" read-only="true"/> <tx:method name="select*" propagation="SUPPORTS" read-only="true"/> <tx:method name="get*" propagation="SUPPORTS" read-only="true"/> <tx:method name="*" propagation="SUPPORTS" read-only="true"/> </tx:attributes> </tx:advice>
3、增加相关代码块
注:利用注解实现动态切换相关数据源
DynamicDataSource.class
/** * 类名:DynamicDataSource.class * 描述:动态数据源类 * -------------------------------------- * 修改内容: * 备注: * Modify by: */ public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { String dataSource =DynamicDataSourceHolder.getDataSourceType(); return dataSource; } }
DynamicDataSourceHolder.class
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * 类名:DynamicDataSourceHolder.class * 描述:获得和设置上下文环境的类,主要负责改变上下文数据源的名称 * -------------------------------------- * 修改内容: * 备注: * Modify by: */ public class DynamicDataSourceHolder { private static final ThreadLocal<String> contextHolder= new ThreadLocal<String>(); public static void setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType); } public static String getDataSourceType() { return contextHolder.get(); } public static void clearDataSourceType() { contextHolder.remove(); } }
DataSourceAspect.class
import org.springframework.aop.AfterReturningAdvice; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; /** * 类名:DataSourceAspect.class * 描述:数据源切面支持,在开启事务之前选择默认的数据源 * -------------------------------------- * 修改内容: * 备注: * Modify by: */ public class DataSourceAspect implements MethodBeforeAdvice,AfterReturningAdvice { public static final String dataSource_sqlserver = "dataSource_sqlserver"; public static final String dataSource_oracle = "dataSource_oracle"; @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { DynamicDataSourceHolder.clearDataSourceType(); } @Override public void before(Method method, Object[] args, Object target) throws Throwable { //首先取类上的数据源 if(method.getDeclaringClass().isAnnotationPresent(DataSource.class) && !method.isAnnotationPresent(DataSource.class)) { DataSource datasource = method.getDeclaringClass().getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSourceType(datasource.name()); //方法上的数据源 优先级高于类上的 } else if (method.isAnnotationPresent(DataSource.class)) { DataSource datasource = method.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSourceType(datasource.name()); } else { DynamicDataSourceHolder.setDataSourceType(dataSource_sqlserver); } } }
DataSource.class
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * 类名:DataSource.class * 描述:数据源切换注解 * -------------------------------------- * 修改内容: * 备注: * Modify by: */ @Documented @Retention(RUNTIME) @Target({ElementType.METHOD,ElementType.TYPE}) public @interface DataSource { String name(); // String name() default DataSource.dataSource_sqlserver; }
调用方法
在如果你的事务控制在service层,建议在controller下调用 添加如下代码块(支持在类和方法级调用)
@DataSource(name = DataSourceAspect.dataSource_oracle)
关于一些疑问:
动态切换数据源以后,需要再切换回来吗?答案:不需要,因为之前已经设置默认的数据源,只有添加注解DataSource的地方,才能改变数据源,如果其他类或者方法没有添加此注解DataSource,将用默认数据源执行数据库操作。
所以,建议在项目初始就将访问不同数据源的controller 或者业务进行分包管理,防止代码混乱
相关文章推荐
- SSM(Spring+SpringMVC+MyBatis)框架详细整合和多数据源配置
- Spring MVC+Mybatis 多数据源配置及发现的几个问题
- SpringMVC+Mybatis 多数据源配置
- spring MVC+MyBatis 多数据源配置
- Spring MVC +MyBatis 多数据源配置
- spring+springMVC+mybatis 多数据源配置
- Spring MVC+Mybatis 多数据源配置
- springmvc+mybatis集成配置
- 使用SSM框架搭建Web服务器实现登录功能(Spring+SpringMVC+Mybatis)
- Spirng+SpringMVC+Maven+Mybatis+MySQL项目搭建
- spring+spring mvc+mybatis+mysql+easyui实现的分页
- Spring+Spring MVC+MyBatis的整合
- 创建一个Spring+SpringMVC+MyBatis+MySql+Maven项目需要注意的地方
- Spring+SpringMVC+MyBatis+easyUI整合基础篇(二)牛刀小试
- SpringMVC+Maven+FreeMarker+MyBatis 使用
- SpringMVC+myBatis简单示例
- springMVC+spring+mybatis 框架下分页查询
- Spring+SpringMVC+mybatis框架环境搭建总结
- Spring4 + Spring MVC + MyBatis 整合思路
- SpringMvc+Mybatis实现一个简单人事管理系统(三)