问题:
使用mybatis时都是用的sqlmapper来做的数据库到java对象的映射,因此在针对一些特定数据库方言使用时无法在多个数据库上切换。
解决方案:
思路:
通过定义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来加载配置文件
思路:
自定义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);
}
分享到:
相关推荐
Mybatis的以传入参数的形式进行切换数据库。
SpringBoot整合mybatis-plus实现多数据源的动态切换且支持分页查询,案例以postgresql和oracle数据库为数据源,分别使用mybatis-plus分页插件和pagehelper分页插件实现分页查询。
完整的Demo结合了springmvc——mybatis,实现了工具类文件上传下载,结合了Redis的初步使用,并且能使用threadlocal实现数据库动态切换,很适合初建项目做参考,适合初学者使用。
项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。 此项目就是为了解决这个问题。
使用springboot + JPA / MyBatis 实现多数据源动态切换
springboot实现数据源动态切换 注意事项: 1. 该demo采用yml配置数据库信息,注意url标签为jdbc-url 2.项目中加了日志输出,可看到完整执行过程 3.在Service中应用事务时,自定义的注解将失效,解决办法:可将注解...
Mybatis+Spring+SpringMVC+quartz多数据源切换 定时任务 多数据库之间同步
springboot+mybatis动态切换数据源完整项目架构,支持mysql与oracle,下载配置数据库信息即可测试。
该资源仅为备份
SpringBoot+gradle+mybatis多数据源动态配置 AOP的方式实现数据源动态切换。
springboot+mybatis+mysql+AbstractRoutingDataSource实现多数据源切换(一写多读数据源)项目中包含完整的demo案例配备文档说明,亲测可用;实现简单,代码思路清晰.
多数据源支持Oracle、Mysql、Sql Server 等数据库夸库操作,使用 @DS 切换数据源。, 可设置多主多从 、纯粹多库(记得设置primary) 、混合配置等; Hutool工具类库,降低相关API的学习成本,提高工作效率;
Spring+SpringMvc+MybatisPlus实现多数据源切换、利用自定义Aop注解,只需要在需要切换数据库的方法上加上注解即可实现、极大避免了代码冗余。
数据库插件 基于SpringBoot2.X+myBatis3.5+以上 集成了 atomikos 解决多数据源的动态切换 同时可以满足对多数据源的事务管理
相信很多朋友在开发的时候,可能会碰到需要一个项目,配置多个数据源的需求,可能是同一种数据库,也可能是不同种类的数据库,这种情况,我们就需要配置多数据源对程序的支持了。 本项目就是一个多数据源的配置,...
可在主流数据库之间任意切换 支持Oracle、MySQL、Postgres、MSSQL、GBase、SQLite、HSQL、Derby等数据库。除了API方式下的操作能兼容各个数据库之外,就连SQL的本地化查询也能使之兼容。JMX动态调节 可以用JMX查看...
springmvc+mybatis结合,多数据源配置,并实现注解aop动态切换,可实现数据库读写分离,maven结构。
spring-boot集成mybatis+druid实现 hive/mysql多数据源切换,用mysql数据库作为用户验证库以及用户信息库,hive作为数据可视化源库。
FastBuilder是一个快速开发以及高性能,高扩展性的ORM框架,灵活支持多数据库切换,读写分离,同时支持Mysql和Oracle数据库, 并且上手快,在DAO层开发效率节约50%以上, 欢迎加入FastBuilder技术交流群:236719790 ...
修改halo持久层框架为mybatis,数据库mysql