mybatis支持多数据库切换

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

思路:

通过定义environment的id来指定使用不同的数据库映射文件,如下
<!--WizRtf2Html Charset=0 -->
<?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);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值