- 浏览: 979991 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
浅谈Spring事务隔离级别:http://www.cnblogs.com/yangy608/archive/2011/06/29/2093478.html
spring里面事务的传播属性和事务隔离级别 :http://blog.csdn.net/it_man/article/details/5074371
第一种方法:创建两个会话工厂
配置如下
这种方法,在程序中只需要切换sqlSessionTemplate即可,但是这样第二数据源无事务,
容易抛出TransactionSynchronizationManager.unbindResourceIfPossible异常,这也是其缺点
是否可以再添加一个事务管理器?
你可以试试,我测试没问题。
jdbc.properties配置文件
第二种方法:扩展数据源路由
查看AbstractRoutingDataSource
//抽象数据源路由
从分析AbstractRoutingDataSource获取数据源得出,想要实现多数据源,只需要扩展AbstractRoutingDataSource,并实现determineCurrentLookupKey方法即可,并在determineCurrentLookupKey方法中切换数据源名即可。
下面实验:
//数据源路由
}
//这里我们创建一个数据源上下文句柄,以便切换数据源
//配置如下
手动测试
访问http://localhost:8080/r/test/db.do控制台输出
2016-09-21 17:57:13 -40921 [com.controller.test.TestController] INFO - =============localDao size:5,dataSource
2016-09-21 17:57:13 -40941 [com.controller.test.TestController] INFO - =============syncDao size:4,syncDataSource
上面的方式是手动切换数据源,下面我们通过Spring AOP实现动态切换数据源:
定义注解
定义AOP
测试
访问http://localhost:8080/r/test/db1.do,控制台输出
2016-09-21 17:58:12 -99217 [com.dataSource.DataSourceAspect] INFO - =============Dao-class:com.controller.test.TestController
2016-09-21 17:58:12 -99220 [com.dataSource.DataSourceAspect] INFO - =============DataSource:dataSource
2016-09-21 17:58:12 -99220 [com.controller.test.TestController] INFO - =======Into testDbSource1==============
2016-09-21 17:58:12 -99225 [com.controller.test.TestController] INFO - =============localDao size:5,dataSource
访问http://localhost:8080/r/test/db2.do,控制台输出
2016-09-21 17:58:16 -104167 [com.dataSource.DataSourceAspect] INFO - =============Dao-class:com.controller.test.TestController
2016-09-21 17:58:16 -104167 [com.dataSource.DataSourceAspect] INFO - =============DataSource:syncDataSource
2016-09-21 17:58:16 -104168 [com.controller.test.TestController] INFO - =======Into testDbSource2==============
2016-09-21 17:58:17 -104180 [com.controller.test.TestController] INFO - =============synDao size:4,syncDataSource
至此动态切换成功,
从上面可以看出,SqlSessionFactoryBean的获取数据源是通过数据源路由,
我们通过扩展数据源路由来实现,动态切换数据源。
注意:
当动态数据源切换失败时,查看是不是事务因素,要先理解事务,例如你的事务是放在service...,你切换数据库时为了保证事务的完整性,你应该在进入service之前切换掉数据源,因为如果你是在service方法中切换数据源那是不可行的,因为这个时候spring已经打开了一个事务,他会阻止你切换,所以你应在这之前切换,然后进入service方法,.这样spring又给你新切换的数据源加上事务了
spring里面事务的传播属性和事务隔离级别 :http://blog.csdn.net/it_man/article/details/5074371
第一种方法:创建两个会话工厂
配置如下
<beans> <!-- 数据源1 --> <bean id="dataSource" 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="${driverClassName}" /> <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}" /> </bean> <!-- 数据源2 --> <bean id="syncDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${sync.url}" /> <property name="username" value="${sync.username}" /> <property name="password" value="${sync.password}" /> <property name="driverClassName" value="${sync.driverClassName}" /> <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}" /> </bean> <!-- 第一个sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property> <!-- mapper扫描 --> <property name="mapperLocations" value="classpath:mybatis/*/*.xml"></property> </bean> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg ref="sqlSessionFactory" /> </bean> <!-- 第二个sqlSessionFactory --> <bean id="syncSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="syncDataSource" /> <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property> <property name="mapperLocations" value="classpath:mybatis/sync/*.xml"></property> </bean> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="syncSqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg ref="syncSqlSessionFactory" /> </bean> <!-- <aop:aspectj-autoproxy proxy-target-class="true" /> --> </beans>
这种方法,在程序中只需要切换sqlSessionTemplate即可,但是这样第二数据源无事务,
容易抛出TransactionSynchronizationManager.unbindResourceIfPossible异常,这也是其缺点
是否可以再添加一个事务管理器?
<bean name="syncTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="syncDataSource"></property> </bean>
你可以试试,我测试没问题。
jdbc.properties配置文件
url=jdbc\:mysql\://localhost\:3306/test?useUnicode\=true&characterEncoding\=utf8&characterSetResults\=utf8 driverClassName=com.mysql.jdbc.Driver username=donald password=123456 #sync datasource sync.url=jdbc\:mysql\://192.168.32.128\:3306/test?useUnicode\=true&characterEncoding\=utf8&characterSetResults\=utf8 sync.driverClassName=com.mysql.jdbc.Driver sync.username=donald sync.password=123456
第二种方法:扩展数据源路由
查看AbstractRoutingDataSource
//抽象数据源路由
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean { public void afterPropertiesSet() { if(targetDataSources == null) throw new IllegalArgumentException("Property 'targetDataSources' is required"); resolvedDataSources = new HashMap(targetDataSources.size()); Object lookupKey; DataSource dataSource; //将配置的多数据源添加到resolvedDataSources中 for(Iterator iterator = targetDataSources.entrySet().iterator(); iterator.hasNext(); resolvedDataSources.put(lookupKey, dataSource)) { java.util.Map.Entry entry = (java.util.Map.Entry)iterator.next(); lookupKey = resolveSpecifiedLookupKey(entry.getKey()); dataSource = resolveSpecifiedDataSource(entry.getValue()); } if(defaultTargetDataSource != null) //默认数据源 resolvedDefaultDataSource = resolveSpecifiedDataSource(defaultTargetDataSource); } //数据源key protected Object resolveSpecifiedLookupKey(Object lookupKey) { return lookupKey; } //获取数据源根据dataSource protected DataSource resolveSpecifiedDataSource(Object dataSource) throws IllegalArgumentException { if(dataSource instanceof DataSource) return (DataSource)dataSource; if(dataSource instanceof String) //从bean容器中获取对应的数据源,(DataSource)beanFactory.getBean(dataSourceName, javax/sql/DataSource); // in BeanFactoryDataSourceLookup.getDataSource(String dataSourceName) return dataSourceLookup.getDataSource((String)dataSource); else throw new IllegalArgumentException((new StringBuilder()).append("Illegal data source value - only [javax.sql.DataSource] and String supported: ").append(dataSource).toString()); } //获取连接 public Connection getConnection() throws SQLException { //再看determineTargetDataSource return determineTargetDataSource().getConnection(); } protected DataSource determineTargetDataSource() { //获取当前数据源名,这里是关键 Object lookupKey = determineCurrentLookupKey(); //获取当前数据源 DataSource dataSource = (DataSource)resolvedDataSources.get(lookupKey); if(dataSource == null && (lenientFallback || lookupKey == null)) //如果dataSource为空,则dataSource为默认的数据源resolvedDataSources dataSource = resolvedDefaultDataSource; if(dataSource == null) throw new IllegalStateException((new StringBuilder()).append("Cannot determine target DataSource for lookup key [").append(lookupKey).append("]").toString()); else return dataSource; } //determineCurrentLookupKey方法,为抽象方法,待子类扩展,这是不是给了我们一种思路 protected abstract Object determineCurrentLookupKey(); private Map targetDataSources;//Map<String,DataSource>,key为数据源名,value为DataSource private Object defaultTargetDataSource; private boolean lenientFallback; private DataSourceLookup dataSourceLookup; private Map resolvedDataSources;//Map<String,DataSource>,key为数据源名,value为DataSource private DataSource resolvedDefaultDataSource; }
从分析AbstractRoutingDataSource获取数据源得出,想要实现多数据源,只需要扩展AbstractRoutingDataSource,并实现determineCurrentLookupKey方法即可,并在determineCurrentLookupKey方法中切换数据源名即可。
下面实验:
//数据源路由
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * 动态切换数据源 * @author donald * */ public class MultipleRoutingDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSourceType(); }
}
//这里我们创建一个数据源上下文句柄,以便切换数据源
/** * 数据源上下文 * @author donald * */ public class DataSourceContextHolder { public final static String DATA_SOURCE_LOCAL = "dataSource"; public final static String DATA_SOURCE_SYNC = "syncDataSource"; //对数据源名,线程隔离 private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static void setDataSourceType(String dataSource) { contextHolder.set(dataSource); } public static String getDataSourceType() { return contextHolder.get(); } public static void clearDataSourceType() { contextHolder.remove(); } }
//配置如下
<beans> <!-- 数据源1 --> <bean id="dataSource" 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="${driverClassName}" /> <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}" /> </bean> <!-- 数据源2 --> <bean id="syncDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${sync.url}" /> <property name="username" value="${sync.username}" /> <property name="password" value="${sync.password}" /> <property name="driverClassName" value="${sync.driverClassName}" /> <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}" /> </bean> <!-- 数据源路由 --> <bean id="multipleDataSource" class="com.dataSource.MultipleRoutingDataSource"> <!-- 默认数据源 --> <property name="defaultTargetDataSource" ref="dataSource"/> <!-- 目标数据源 --> <property name="targetDataSources"> <map> <!-- 注意这里的value是和上面的DataSource的id对应,key要和 下面的DataSourceContextHolder中的常量对应 --> <entry value-ref="dataSource" key="dataSource"/> <entry value-ref="syncDataSource" key="syncDataSource"/> </map> </property> </bean> <!-- 配置mybatis --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 这里为multipleDataSource,可以统一管理事务 --> <property name="dataSource" ref="multipleDataSource" /> <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property> <!-- mapper扫描 --> <property name="mapperLocations" value="classpath:mybatis/*/*.xml"></property> </bean> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg ref="sqlSessionFactory" /> </bean> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="multipleDataSource"></property> </bean> <!-- <aop:aspectj-autoproxy proxy-target-class="true" /> --> </beans>
手动测试
@Controller @RequestMapping(value="/test") public class TestController extends BaseController{ private static Logger log = LoggerFactory.getLogger(TestController.class); @Resource(name = "daoSupport") private DaoSupport dao; @SuppressWarnings("unchecked") @RequestMapping("/db") public void testDbSource(HttpServletResponse response) throws IOException { log.debug("=======Into testDbSource=============="); PageData pd = this.getPageData(); try { DataSourceContextHolder.setDataSourceType(DataSourceContextHolder.DATA_SOURCE_LOCAL); List<PageData> lpd = (List<PageData>) dao.findForList("test.list", pd); log.info("=============localDao size:"+lpd.size()+","+DataSourceContextHolder.getDataSourceType()); DataSourceContextHolder.clearDataSourceType(); } catch (Exception e) { log.error(e.getMessage()); e.printStackTrace(); } try { DataSourceContextHolder.setDataSourceType(DataSourceContextHolder.DATA_SOURCE_SYNC); List<PageData> lpdTest = (List<PageData>) dao.findForList("test.list", pd); log.info("=============syncDao size:"+lpdTest.size()+","+DataSourceContextHolder.getDataSourceType()); DataSourceContextHolder.clearDataSourceType(); } catch (Exception e) { log.error(e.getMessage()); e.printStackTrace(); } response.getWriter().write("test"); } }
访问http://localhost:8080/r/test/db.do控制台输出
2016-09-21 17:57:13 -40921 [com.controller.test.TestController] INFO - =============localDao size:5,dataSource
2016-09-21 17:57:13 -40941 [com.controller.test.TestController] INFO - =============syncDao size:4,syncDataSource
上面的方式是手动切换数据源,下面我们通过Spring AOP实现动态切换数据源:
定义注解
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DbSource { String value() default ""; }
定义AOP
/** * 根据DAO的DbSource的值,动态切换数据源 * @author donald * */ @Aspect @Component public class DataSourceAspect { private static final Logger log = LoggerFactory.getLogger(DataSourceAspect.class); //定义切点 @Pointcut("@annotation(com.fh.dataSource.DbSource)") public void dbSourceAspect() {} /* @Before("dbSourceAspect()") public void doBefore(JoinPoint joinPoint) { try { System.out.println("Dao-class:" + (joinPoint.getTarget().getClass().getName())); System.out.println("DataSource:" + getDbSourceValue(joinPoint)); } catch (Exception e) { // 记录本地异常日志 logger.error("exception", e.getMessage()); } }*/ /** * 切换数据源 * @param joinPoint */ /*有参数的处理 Object[] args = joinPoint.getArgs(); if(args != null && args.length > 1) { log.info("==============Around-args:"+JsonUtil.toJson(args)); obj = joinPoint.proceed(args); } else{ obj = joinPoint.proceed(); }*/ @Around("dbSourceAspect()") public void doAround(ProceedingJoinPoint joinPoint) { try { log.info("=============Dao-class:" + (joinPoint.getTarget().getClass().getName())); log.info("=============DataSource:" + getDbSourceValue(joinPoint)); joinPoint.proceed(); DataSourceContextHolder.clearDataSourceType(); } catch(Throwable e){ log.error("=============Throwable:", e.getMessage()); } } /** * 切换数据源,当注解方法有返回值的处理情况 * @param joinPoint */ /* @Around("dbSourceAspect()") public Object doAround(ProceedingJoinPoint joinPoint) { //切入方法返回对象 Object obj = null; try { log.debug("=============class:" + (joinPoint.getTarget().getClass().getName())); log.debug("=============DataSource:" + getDbSourceValue(joinPoint)); obj = joinPoint.proceed(); } catch(Throwable e){ log.error("=============Throwable:", e.getMessage()); e.printStackTrace(); } finally{ DataSourceContextHolder.clearDataSourceType(); } return obj; } */ /** * 获取数据源id * @param joinPoint * @return * @throws Exception */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static String getDbSourceValue(JoinPoint joinPoint) throws Exception { //根据连接点获取class String targetName = joinPoint.getTarget().getClass().getName(); Class targetClass = Class.forName(targetName); // DbSource dbSource = (DbSource) targetClass.getAnnotation(DbSource.class); //根据连接点获取method String methodName = joinPoint.getSignature().getName(); //根据连接点获取args Object[] arguments = joinPoint.getArgs(); Method[] methods = targetClass.getMethods(); String dbId =""; //获取注解连接点的值 for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == arguments.length) { dbId = method.getAnnotation(DbSource.class).value(); if(!StringUtils.isBlank(dbId)){ DataSourceContextHolder.setDataSourceType(dbId); } else{ dbId = DataSourceContextHolder.DATA_SOURCE_LOCAL; DataSourceContextHolder.setDataSourceType(DataSourceContextHolder.DATA_SOURCE_LOCAL); } break; } } } return dbId; } }
测试
@Controller @RequestMapping(value="/test") public class TestController extends BaseController{ private static Logger log = LoggerFactory.getLogger(TestController.class); @Resource(name = "daoSupport") private DaoSupport dao; @SuppressWarnings("unchecked") @RequestMapping("/db1") @DbSource(DataSourceContextHolder.DATA_SOURCE_LOCAL) public void testDbSource1(HttpServletResponse response) throws IOException { log.info("=======Into testDbSource1=============="); PageData pd = this.getPageData(); try { List<PageData> lpd = (List<PageData>) dao.findForList("test.list", pd); log.info("=============localDao size:"+lpd.size()+","+DataSourceContextHolder.getDataSourceType()); } catch (Exception e) { log.error(e.getMessage()); e.printStackTrace(); } response.getWriter().write("db1"); } @SuppressWarnings("unchecked") @RequestMapping("/db2") @DbSource(DataSourceContextHolder.DATA_SOURCE_SYNC) public void testDbSource2(HttpServletResponse response) throws IOException { log.info("=======Into testDbSource2=============="); PageData pd = this.getPageData(); try { List<PageData> lpdTest = (List<PageData>) dao.findForList("test.list", pd); log.info("=============synDao size:"+lpdTest.size()+","+DataSourceContextHolder.getDataSourceType()); } catch (Exception e) { log.error(e.getMessage()); e.printStackTrace(); } response.getWriter().write("db2"); } }
访问http://localhost:8080/r/test/db1.do,控制台输出
2016-09-21 17:58:12 -99217 [com.dataSource.DataSourceAspect] INFO - =============Dao-class:com.controller.test.TestController
2016-09-21 17:58:12 -99220 [com.dataSource.DataSourceAspect] INFO - =============DataSource:dataSource
2016-09-21 17:58:12 -99220 [com.controller.test.TestController] INFO - =======Into testDbSource1==============
2016-09-21 17:58:12 -99225 [com.controller.test.TestController] INFO - =============localDao size:5,dataSource
访问http://localhost:8080/r/test/db2.do,控制台输出
2016-09-21 17:58:16 -104167 [com.dataSource.DataSourceAspect] INFO - =============Dao-class:com.controller.test.TestController
2016-09-21 17:58:16 -104167 [com.dataSource.DataSourceAspect] INFO - =============DataSource:syncDataSource
2016-09-21 17:58:16 -104168 [com.controller.test.TestController] INFO - =======Into testDbSource2==============
2016-09-21 17:58:17 -104180 [com.controller.test.TestController] INFO - =============synDao size:4,syncDataSource
至此动态切换成功,
从上面可以看出,SqlSessionFactoryBean的获取数据源是通过数据源路由,
我们通过扩展数据源路由来实现,动态切换数据源。
注意:
当动态数据源切换失败时,查看是不是事务因素,要先理解事务,例如你的事务是放在service...,你切换数据库时为了保证事务的完整性,你应该在进入service之前切换掉数据源,因为如果你是在service方法中切换数据源那是不可行的,因为这个时候spring已经打开了一个事务,他会阻止你切换,所以你应在这之前切换,然后进入service方法,.这样spring又给你新切换的数据源加上事务了
发表评论
-
Mybatis缓存实现
2016-12-07 10:36 978SqlSessionFactory初始化:http://don ... -
DefaultSqlSession第三讲-事务提交,回滚,关闭SqlSession,清除缓存
2016-11-20 11:07 5695上面两篇讲过query和update及flushStateme ... -
DefaultSqlSession第二讲-更新,刷新Statement
2016-11-20 11:06 627上一篇文章中,我们讲到DefaultSqlSession的查询 ... -
DefaultSqlSession第一讲query解析
2016-11-20 11:06 1619上一篇文章:我们说过DefaultSqlSession,Def ... -
Mybatis的SqlSession解析
2016-11-20 11:02 2542在前文中,Mybatis使用教程中,有下面一段代码: Sql ... -
Mybatis的Reflector解析
2016-11-18 12:53 2157Mybatis的MetaObject解析:http://don ... -
Mybatis的MetaObject解析
2016-11-18 11:40 9575SqlSessionFactory初始化:http://don ... -
mybatis 动态标签语句的解析(BoundSql)
2016-10-30 09:48 5752SqlSessionFactory初始化:http://don ... -
Mybatis的Environment解析详解
2016-10-29 18:28 1991SqlSessionFactory初始化:http://don ... -
Mybatis 解析Mapper(class)
2016-10-26 11:44 3342SqlSessionFactory初始化:http://don ... -
Mybatis加载解析Mapper(xml)文件第二讲
2016-10-25 21:30 4780SqlSessionFactory初始化:http://don ... -
Mybatis加载解析Mapper(xml)文件第一讲
2016-10-25 16:51 6172SqlSessionFactory初始化:http://don ... -
SqlSessionFactory初始化
2016-10-20 15:38 2453mybatis 使用教程:http://donald-drap ... -
mybatis 使用教程
2016-10-14 09:03 906Myeclispe下mybatis generator的使 ... -
Spring的RequestMappingHandlerMapping详解
2016-09-23 08:40 4591深刻理解IdentityHashMap:http://dona ... -
Spring-RequestMappingHandlerAdapter初始化及请求处理
2016-09-22 11:50 10572看这篇文章之前,最好先看下面这篇,以便更好的理解handler ... -
Spring的DefaultAnnotationHandlerMapping详解
2016-09-20 08:47 5839前面我们讲解过Dispatcher ... -
Spring-DispatcherServlet请求处理
2016-09-19 15:42 1684Spring-DispatcherServlet初始化详解:h ... -
Spring-DispatcherServlet初始化详解
2016-09-19 15:03 3689Spring-DispatcherServlet请求处理:ht ... -
Spring上下文加载监听器ContextLoaderListener--源码解析
2016-09-18 18:10 4655一般在web应用配置Spring上下文如下,那么Context ...
相关推荐
对于MyBatis,我们需要创建`mybatis-config.xml`配置文件,配置数据源、事务管理器以及映射文件的位置。 数据库方面,本系统使用了MySQL,通过MyBatis的SqlSessionFactory和SqlSession对象,我们可以执行SQL语句。`...
在多数据源配置中,Spring能够帮助管理不同的数据源,通过配置bean来切换和控制数据源的使用。 **SpringMVC** 是Spring框架的一部分,专为Web开发设计。它简化了模型-视图-控制器(Model-View-Controller,MVC)的...
- MyBatis的配置文件(mybatis-config.xml)中,设置数据源和SqlSessionFactory,以便MyBatis与数据库交互。 通过以上步骤,我们可以构建一个松耦合、可测试的系统,每个组件都发挥着它应有的作用,而注解方式的...
总之,Spring+MyBatis多数据源配置是大型项目中常见的需求,它通过`AbstractRoutingDataSource`实现了动态数据源选择,结合MyBatis的Mapper接口和注解,可以方便地在多个数据库之间切换,从而满足复杂的数据库访问...
"spring+hibernate和spring+myBatis实现连接多个数据库,同时操作的项目"是针对这种需求的一个解决方案,旨在提供一种灵活且动态的数据源切换机制。 首先,Spring框架作为Java领域中最受欢迎的应用框架之一,其强大...
1. **配置文件**:包括Spring的bean配置文件(如`applicationContext.xml`)和MyBatis的配置文件(如`mybatis-config.xml`),它们定义了数据源、事务管理器、SqlSessionFactory以及Mapper接口的扫描路径。...
4. 配置Spring:创建Spring的配置文件(如applicationContext.xml),声明bean,包括Action、Service、DAO以及数据源等。 5. 配置MyBatis:设置mybatis-config.xml,配置数据源和Mapper接口。 6. 编写Service和DAO:...
3. **配置MyBatis**:编写MyBatis的配置文件,包括数据源、SqlSessionFactory,并为每个Mapper接口定义XML映射文件。 4. **整合Spring和Struts2**:使用Spring的Struts2插件,使Spring管理的Bean可以直接在Struts2 ...
综上所述,通过Spring Boot、Mybatis和Druid,我们可以灵活地管理多个数据库,实现数据源的动态切换。在实际项目中,这有助于提高系统的灵活性和可扩展性。多数据源配置对于处理分布式系统、读写分离、数据库分片等...
总结来说,"Spring+SpringMVC+Mybatis多数据源"的整合涉及了Spring的数据源管理、SpringMVC的请求路由、Mybatis的数据源配置以及事务管理。具体实现时,可以根据项目需求选择合适的方式进行数据源切换,以达到优化...
5. **MyBatis配置**:在多数据源环境下,MyBatis的配置需要针对每个数据源分别设置SqlSessionFactory,并在Mapper接口上通过@MapperScan注解指定对应的SqlSessionFactory。 6. **事务管理**:在多数据源情况下,...
标题中的"struts+spring+mybatis源代码例子"意味着这是一个实际的项目示例,包含了这三个框架的集成使用,可以帮助开发者理解和学习如何在实际项目中整合这些技术。通过分析和研究这个源代码,开发者可以深入理解...
在实际项目中,开发者通常会创建一个配置文件(如:`springmvc_mybatis1208`可能包含的`spring-config.xml`),在其中配置Spring和MyBatis的相关设置,包括数据源、事务管理器、SqlSessionFactory等。同时,还需要...
本套源代码实现了Spring 和 mybatis 和 layui 集成情况下的基础操作,包括: 增删改查、分页、导入导出等功能。数据库为mysql,脚本在源代码根目录下,mybatis_crud.sql
这篇博客“Spring+Mybatis 多数据源配置”将深入探讨如何在项目中实现这一功能。 首先,我们需要理解多数据源的概念。在传统的单数据源配置中,所有的数据库访问都指向同一个数据库。而在多数据源环境中,不同的...
总结,Spring Boot结合Mybatis和Druid实现多数据源配置的过程包括:配置数据源、配置Mybatis、创建数据源切换器、以及针对不同数据库的测试。这一过程涉及了Spring Boot的自动配置、依赖注入、配置属性绑定等多个...
spring +springboot+mybatis+maven 读写分离,数据库采用mysql, 采用springboot 采用项目框架搭建,继承spring 中的AbstractRoutingDataSource,实现 determineCurrentLookupKey 进行数据源的动态切换,采用Spring ...
- `spring-mybatis.xml`中配置数据源、事务管理器、MyBatis的SqlSessionFactory以及Mapper扫描器。 - `spring-mvc.xml`中配置DispatcherServlet、视图解析器、拦截器等。 6. **资源文件** - 配置数据库连接的`...
`SpringBoot`、`MyBatis` 和 `HikariCP` 的结合是目前广泛采用的一种高效、灵活的解决方案,特别是对于处理多数据源场景。这个项目组合利用了它们各自的优势,减少了开发人员的工作量,提高了系统的性能。 首先,`...