mybatis支持多数据库切换

使用mybatis时都是用的sqlmapper来做的数据库到java对象的映射,因此在针对一些特定数据库方言使用时无法在多个数据库上切换。
解决方案:
  • mybatis篇

思路:

通过定义environment的id来指定使用不同的数据库映射文件,如下
<!--WizRtf2Html Charset=0 -->
  1. <?xml version="1.0" encoding="UTF-8" ?>   
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">  
  3. <configuration>      
  4. <environments default="mysql">          
  5. <environment id="mysql">              
  6. <transactionManager type="JDBC" />              
  7.     <dataSource type="POOLED">                  
  8.         <property name="driver" value="com.mysql.jdbc.Driver" />                  
  9.         <property name="url" value="jdbc:mysql://localhost:3306/test" />                  
  10.         <property name="username" value="root" />                  
  11.         <property name="password" value="pwd" />              
  12.     </dataSource>          
  13. </environment>      
  14. </environments>      
  15.     <mappers>          
  16.     <mapper resource="cn/dcr/mybatis/entity/UserMapper.xml" />      
  17.     </mappers>  
  18. </configuration>  
<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>    
<environments default="mysql">        
<environment id="mysql">            
<transactionManager type="JDBC" />            
	<dataSource type="POOLED">                
		<property name="driver" value="com.mysql.jdbc.Driver" />                
		<property name="url" value="jdbc:mysql://localhost:3306/test" />                
		<property name="username" value="root" />                
		<property name="password" value="pwd" />            
	</dataSource>        
</environment>    
</environments>    
	<mappers>        
	<mapper resource="cn/dcr/mybatis/entity/UserMapper.xml" />    
	</mappers>
</configuration>
environment的id是mysql映射文件是cn/dcr/mybatis/entity/UserMapper.xml
那么mybatis实际是读取的mysql/cn/dcr/mybatis/entity/UserMapper.xml
 

实现:

以org.apache.ibatis.builder.xml.XMLConfigBuilder类为蓝本创建一个新类org.apache.ibatis.builder.xml.XMLConfigBuilderEx
添加一个成员变量
private String dialect;
修改environmentsElement方法设置方言
private void environmentsElement(XNode context) throws Exception {
if (context != null) { if (environment == null) { environment = context.getStringAttribute("default"); } for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); dialect = id.toLowerCase();//设置方言 if (isSpecifiedEnvironment(id)) { TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory).dataSource(dsFactory.getDataSource()); configuration.setEnvironment(environmentBuilder.build()); } } } }
修改mapperElement方法
private void mapperElement(XNode parent) throws Exception {
if (parent != null) { for (XNode child : parent.getChildren()) { String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); InputStream inputStream; if (resource != null && url == null) { if(dialect != null){ resource = dialect + "/" + resource;//从方言指定位置查找 } ErrorContext.instance().resource(resource); inputStream = Resources.getResourceAsStream(resource); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); mapperParser.parse(); } else if (url != null && resource == null) { if(dialect != null){ url = dialect + "/" + url;//从方言指定位置查找 } ErrorContext.instance().resource(url); inputStream = Resources.getUrlAsStream(url); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } else { throw new BuilderException("A mapper element may only specify a url or resource, but not both."); } } } }
继承org.apache.ibatis.session.SqlSessionFactoryBuilder类创建一个新类org.apache.ibatis.session.SqlSessionFactoryBuilderEx用来加载org.apache.ibatis.builder.xml.XMLConfigBuilderEx
覆盖父类中的build方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties props) { try { XMLConfigBuilderEx parser = new XMLConfigBuilderEx(inputStream, environment, props); Configuration config = parser.parse(); return build(config); } catch (Exception e) { throw ExceptionFactory.wrapException( "Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } }
调用org.apache.ibatis.builder.xml.XMLConfigBuilderEx来加载配置文件
 
  • spring篇

思路:

自定义mybatis配置加载Bean在spring的配置文件中添加方言的配置让自定义Bean在加载mybatis的配置时可以使用不同的数据库映射文件,如下
<bean id= "sqlSessionFactory" class= "org.mybatis.spring.SqlSessionFactoryBeanEx">
<property name= "dataSource" ref= "dataSource" /> <property name= "configLocation" value= "classpath:configuration.xml" /> <property name= "mapperLocations" value= "classpath*:${jdbc.dialect}/mappers/*.xml" /> </bean>
${jdbc.dialect}在配置文件中设置,如mysql,那么spring会把mysql/mappers下的所有映射文件加载进来

实现:

以org.mybatis.spring.SqlSessionFactoryBean为蓝本创建org.mybatis.spring.SqlSessionFactoryBeanEx类
将成员变量
private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
修改为
private SqlSessionFactoryBuilderEx sqlSessionFactoryBuilderEx = new SqlSessionFactoryBuilderEx();
并去掉setSqlSessionFactoryBuilder方法添加setSqlSessionFactoryBuilderEx方法
覆盖buildSqlSessionFactory方法
protected SqlSessionFactory buildSqlSessionFactory() throws IOException, IllegalAccessException, InstantiationException {
XMLConfigBuilderEx xmlConfigBuilderEx; Configuration configuration;
if (this.configLocation != null) { try { xmlConfigBuilderEx = new XMLConfigBuilderEx(this.configLocation.getInputStream(), null, this.configurationProperties); configuration = xmlConfigBuilderEx.parse(); } catch (Exception ex) { throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex); } finally { ErrorContext.instance().reset(); }
if (this.logger.isDebugEnabled()) { this.logger.debug("Parsed configuration file: '" + this.configLocation + "'"); } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration"); } configuration = new Configuration(); }
if (this.transactionFactory == null) { this.transactionFactory = new SpringManagedTransactionFactory(this.dataSource); }
Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);
configuration.setEnvironment(environment);
if (!ObjectUtils.isEmpty(this.mapperLocations)) { Map<String, XNode> sqlFragments = new HashMap<String, XNode>();
for (Resource mapperLocation : this.mapperLocations) { if (mapperLocation == null) { continue; }
// MyBatis holds a Map using "resource" name as a key. // If a mapper file is loaded, it searches for a mapper // interface type. // If the type is found then it tries to load the mapper file // again looking for this: // // String xmlResource = type.getName().replace('.', '/') + // ".xml"; // // So if a mapper interface exists, resource cannot be an // absolute path. // Otherwise MyBatis will throw an exception because // it will load both a mapper interface and the mapper xml file, // and throw an exception telling that a mapperStatement cannot // be loaded twice. String path; if (mapperLocation instanceof ClassPathResource) { path = ((ClassPathResource) mapperLocation).getPath(); } else { // this won't work if there is also a mapper interface in // classpath path = mapperLocation.toString(); }
try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), configuration, path, sqlFragments); xmlMapperBuilder.parse(); } catch (Exception e) { throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e); } finally { ErrorContext.instance().reset(); }
if (this.logger.isDebugEnabled()) { this.logger.debug("Parsed mapper file: '" + mapperLocation + "'"); } } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Property 'mapperLocations' was not specified, only MyBatis mapper files specified in the config xml were loaded"); } }
return this.sqlSessionFactoryBuilderEx.build(configuration); }

 

转载于:https://www.cnblogs.com/youngdream-ppj/archive/2013/02/22/2922968.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值