您的位置:首页 > 数据库 > MySQL

MySQL Replication 同步复制技术介绍

2012-03-27 15:52 357 查看

问题:

使用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 voidenvironmentsElement(XNode context) throwsException {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"));DataSourceFactorydsFactory = dataSourceElement(child.evalNode("dataSource"));Environment.BuilderenvironmentBuilder = newEnvironment.Builder(id).transactionFactory(txFactory).dataSource(dsFactory.getDataSource());configuration.setEnvironment(environmentBuilder.build());}}}}
修改mapperElement方法[code]
private voidmapperElement(XNode parent) throws Exception{if (parent != null) {for (XNode child :parent.getChildren()) {String resource = child.getStringAttribute("resource");String url = child.getStringAttribute("url");InputStreaminputStream;if (resource!= null && url== null) {if(dialect !=null){resource = dialect+ "/" + resource;//从方言指定位置查找}ErrorContext.instance().resource(resource);inputStream=Resources.getResourceAsStream(resource);XMLMapperBuildermapperParser = newXMLMapperBuilder(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);XMLMapperBuildermapperParser = newXMLMapperBuilder(inputStream, configuration, url,configuration.getSqlFragments());mapperParser.parse();}else {throw newBuilderException("A mapper element may only specify a url orresource, but notboth.");}}}}
继承org.apache.ibatis.session.SqlSessionFactoryBuilder类创建一个新类org.apache.ibatis.session.SqlSessionFactoryBuilderEx用来加载org.apache.ibatis.builder.xml.XMLConfigBuilderEx覆盖父类中的build方法
public SqlSessionFactory build(InputStreaminputStream, String environment, Properties props) {try {XMLConfigBuilderEx parser = newXMLConfigBuilderEx(inputStream, environment,props);Configuration config =parser.parse();returnbuild(config);} catch (Exceptione) {throwExceptionFactory.wrapException("Error buildingSqlSession.", e);} finally{ErrorContext.instance().reset();try{inputStream.close();} catch (IOException e) {// Intentionally ignore. Prefer previouserror.}}}
调用org.apache.ibatis.builder.xml.XMLConfigBuilderEx来加载配置文件

spring篇

思路:

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

实现:

以org.mybatis.spring.SqlSessionFactoryBean为蓝本创建org.mybatis.spring.SqlSessionFactoryBeanEx类将成员变量
private SqlSessionFactoryBuildersqlSessionFactoryBuilder = newSqlSessionFactoryBuilder();
修改为
private SqlSessionFactoryBuilderExsqlSessionFactoryBuilderEx = newSqlSessionFactoryBuilderEx();
并去掉setSqlSessionFactoryBuilder方法添加setSqlSessionFactoryBuilderEx方法覆盖buildSqlSessionFactory方法
protected SqlSessionFactory buildSqlSessionFactory()throws IOException, IllegalAccessException,InstantiationException {XMLConfigBuilderExxmlConfigBuilderEx;Configurationconfiguration;if (this.configLocation !=null) {try{xmlConfigBuilderEx = new XMLConfigBuilderEx(this.configLocation.getInputStream(), null, this.configurationProperties);configuration= xmlConfigBuilderEx.parse();} catch (Exception ex) {throw newNestedIOException("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 MyBatisConfiguration");}configuration = newConfiguration();}if (this.transactionFactory == null) {this.transactionFactory =new SpringManagedTransactionFactory(this.dataSource);}Environmentenvironment = newEnvironment(this.environment, this.transactionFactory, this.dataSource);configuration.setEnvironment(environment);if (!ObjectUtils.isEmpty(this.mapperLocations)) {Map<String, XNode>sqlFragments = newHashMap<String, XNode>();for (Resource mapperLocation : this.mapperLocations){if (mapperLocation == null) {continue;}// MyBatis holds a Map using "resource" name as akey.// If a mapper file isloaded, it searches for a mapper// interface type.// If the type is found then it tries to load the mapperfile// again looking forthis://// StringxmlResource = type.getName().replace('.', '/') +// ".xml";//// So if a mapperinterface exists, resource cannot be an// absolute path.//Otherwise MyBatis will throw an exceptionbecause// it will load both amapper interface and the mapper xml file,// and throw an exception telling that a mapperStatementcannot// be loadedtwice.String path;if (mapperLocation instanceof ClassPathResource){path = ((ClassPathResource)mapperLocation).getPath();} else {//this won't work if there is also a mapper interfacein//classpathpath =mapperLocation.toString();}try {XMLMapperBuilderxmlMapperBuilder = newXMLMapperBuilder(mapperLocation.getInputStream(), configuration, path,sqlFragments);xmlMapperBuilder.parse();}catch (Exception e){throw new NestedIOException("Failed toparse mapping resource: '" + mapperLocation+ "'",e);} finally{ErrorContext.instance().reset();}if (this.logger.isDebugEnabled()){this.logger.debug("Parsed mapperfile: '" + mapperLocation + "'");}}}else {if (this.logger.isDebugEnabled()){this.logger.debug("Property 'mapperLocations' was not specified, only MyBatis mapperfiles specified in the config xml wereloaded");}}return this.sqlSessionFactoryBuilderEx.build(configuration);}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: