原文地址:
http://www.ibm.com/developerworks/cn/java/j-lo-dynamicpersist/
前言
我们时常会遇到一些 web 项目,需要从不同的数据源中抓取数据来进行分析,而这些数据源是有可能变化的,需要用户来进行动态的维护和添加。可是,大多数的 web 程序使用了应用服务器或者容器中间件来管理数据源的生命周期,因此数据源的变化自然不能够独立于程序,而需要由专业人士去进行维护,必要时还需要重新发布程序来适应数据源的变化,而且数据源的个数、数据库的类型也都会有所限制。
那么怎样才可以突破以上这些局限,彻底实现由用户远程对数据源进行维护和管理的需求呢?本文提出了一个有效的解决方案,该方案的大体思路如下:将数据源的配置信息保存在一个地址相对固定的数据库或本地文件系统中,系统将依据这些配置信息自动生成数据源(每当数据信息发生变化时,系统将重新生成新数据源),然后通过工厂模式的持久层将这些数据源自动分配给对应的类对象使用。如此,只需要一个用户界面,来对此数据源的配置信息进行管理,就可以实现由用户自主维护数据源系统的目的了。下文将以一个 Spring+iBATIS 框架的实例,来详细描述该解决方案的实现。
回页首
相关技术介绍
iBATIS
Apache iBATIS 是 Clinton Begin 开发,现在由 Apache 基金会支持的用于加快 JDBC 编程的经过泛化的框架,是当前 IT 项目中使用很广泛的一个半自动 ORM 框架,区别于 Hibernate 之类的全自动框架,iBATIS 对数据库的操作拥有更加灵活的控制,对于那些经常需要调用本地数据库函数自定义 SQL 语句,或是喜欢自己优化 SQL 执行效率的开发者来说,iBATIS 是一个非常不错的选择。而得到广泛应用的开源企业架构 Spring Framework,也很好的将 iBATIS 进行了集成,使得 iBATIS 在 Spring 中的使用更加便利、快捷。下面是 iBATIS 的一些关键组件:
SqlMapClient:是 iBATIS 的重要接口,是线程安全的。这个接口涉及到对 SQL 映射的执行和批处理。
Sqlmap-config.xml:是使用 iBATIS 的起点,负责把所有的 SQL 映射文件(sqlmap.xml)组合在一起。该配置文件可以告诉 iBATIS 如何连接数据库,以及获取哪些 SQL 映射文件(sqlmap.xml)。
sqlmap.xml包含了我们将要运行的 SQL 语句,被 Sqlmap-config.xml 文件所引用。
图 1.iBATIS 架构图
我们之所以选用 iBATIS 而不是 Hibernate 来作为本解决方案的开发框架,主要是因为相比 Hibernate 来说 iBATIS 更具灵活性,可以更为方便地对其结构进行改写。尤其是在对不同数据库结构的封装方面,iBATIS 更适用于对实现相同逻辑的不同数据库结构的支持。反观 Hibernate 则需要对数据库结构进行封装,这就意味着对不同的数据库结构要生成不同的 PO 类,这会使开发工作变得繁琐。当然用户也可以选择使用 Hibernate 来作为框架,其理念是相同的,不同的只是实现手段。
Spring 对 iBATIS 的支持
Spring 通过 DAO 模式,提供了对 iBATIS 的良好支持。
SqlMapClient:是 iBATIS 中的主要接口,通过 xml 配置文件可以让 Spring 容器来管理 SqlMapClient 对象的创建,Spring 提供了 SqlMapClientFactoryBean 来生成该对象。
SqlMapClientFactoryBean:SqlMapClientFactoryBean 是由 Spring 所提供的,用来生成 SqlMapClient 对象的一个工厂类。当使用 Spring 配置文件将 SqlMapClientFactoryBean 作为一个 SqlMapClient 的实现类进行注入时,Spring 容器将根据接口里的定义来调用其 getObject 方法,最终返回一个 SqlMapClient 接口的实现类。SqlMapClientFactoryBean 生成的对象拥有两个重要属性,configLocation 属性用来确定 sqlmap-config.xml,dataSource 属性用来确定数据源。
SqlMapClientDaoSupport:Spring 提供的数据库操作类,应用程序的持久层 DAO 则可以继承这个类。SqlMapClientDaoSupport 需要 Spring 为其注入 SqlMapClient 接口的实现对象,来确定使用何种数据源和使用何种 sqlmap-config.xml。
回页首
持久层的架构和设计
如上节所述可知,如果要使传统的 Spring+iBATIS 框架支持动态的多数据源持久层,则需要对其进行改良。而数据源是由 SqlMapClient 对象的属性所定义的,所以要想办法通过变更 SqlMapClient 接口的实现对象来达到目的。Spring 是使用 XML 配置文件来存储 SqlMapClient 对象的信息,因此只需要能够根据数据源配置信息来动态生成该 XML 配置文件,来实现对 SqlMapClient 接口的动态注入即可。
图 2. 持久层架构流程图(查看大图)
持久层架构的具体处理流程如上图所示:
1.创建配置文件生成类 SqlMapClientFactory,当应用服务器启动时,Spring 框架将启动 SqlMapClientFactory 类的 init 方法(每当数据源配置信息发生变化时也重新启动此方法),该方法将读取数据库或本地文件系统中存储的数据源配置信息,然后动态的生成 Spring XML 配置文件。在此 XML 配置文件中,根据不同的数据源定义了很多不同的 SqlMapClient 对象,并定义了其相对应的数据源和 sqlmap-config 文件。
2.创建 SqlMapClient 接口的实现类 RoutingSqlMapClient,并通过 Spring 将生成的所有 SqlMapClient 对象以 Map 的结构形式注入到 RoutingSqlMapClient 中,当其被调用时将根据要求使用相应的 SqlMapClient 实现对象来对 RoutingSqlMapClient 的方法进行重写。
3.将 RoutingSqlMapClient 注入到所有继承了 SqlMapClientDaoSupport 的 DAO 实现类中,DAO 将根据实际需求决定使用哪个数据源。
回页首
持久层的具体实现
使用 SqlMapClientFactory 类生成 XML 配置文件
如上文的描述,第一步应该创建 SqlMapClientFactory 类,并创建一个用来生成 SqlMapClient 的 XML 配置文件的方法。然后配置 Spring,使其能在程序启动时自动调用 SqlMapClient 的该方法。该方法要从本地文件系统或地址相对固定的数据库系统中读取数据源配置信息,SqlMapClientFactory 所读取的数据源配置信息的主要字段如下:
注:<hostname> 是数据库所在的服务器地址,<portNum> 是数据库所用服务端口号,<databaseName> 是数据库名称,<userName> 是数据库用户名,<password> 是该用户的密码
表 1 数据源配置信息
ID Name Connection User Password DBType
00001 PROJECTA jdbc:db2://<hostname>:<portNum>/<databaseName> <userName> <password> DB2
00002 PROJECTB jdbc:microsoft:sqlserver://<hostname>:
<portNum>;DatabaseName=<databaseName> <userName> <password> sqlserver
00003 PROJECTC jdbc:db2://<hostname>:<portNum>/<databaseName> <userName> <password> DB2
00004 PROJECTD jdbc:db2://<hostname>:<portNum>/<databaseName> <userName> <password> DB2
SqlMapClientFactory 将根据这些配置信息生成相应的 SqlMapClient 对象的 XML 配置文件。下面详细介绍一下该 XML 配置文件的主要构成。
1,根据数据源配置信息的 ID 和 Name,生成所有 SqlMapClient 接口实现对象的 Map 列表。
清单 1. routingSqlMapClient 配置
<bean id="routingSqlMapClient" class="com.ibm.mbps.tsd.dao.RoutingSqlMapClient">
<property name="targetSqlMapClients">
<map key-type="java.lang.String">
<entry key="PROJECTA" value-ref="sqlmapClient_00001"/>
<entry key="PROJECTB" value-ref="sqlmapClient_00002"/>
<entry key="PROJECTC" value-ref="sqlmapClient_00003"/>
<entry key="PROJECTD" value-ref="sqlmapClient_00004"/>
……
</map>
</property>
</bean>
2,为每个 SqlMapClient 接口实现对象创建数据源,数据源根据上文的配置信息生成。
清单 2. data source 配置示例
<bean id="datasource_00001" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>com.ibm.db2.jcc.DB2Driver</value>
</property>
<property name="url">
<value> jdbc:db2://hostname:portNum/databaseName</value>
</property>
<property name="username">
<Value>userName</value>
</property>
<property name="password">
<value>password</value>
</property>
</bean>
3,为每个 SqlMapClient 对象注入数据源和 sqlmap-config 配置文件,应该注意的是该 sqlmap-config 配置文件是针对某一类数据源的,比如多个数据源的数据库类型和数据库内容都相同,那么就应该使用同一张配置文件。
清单 3. SqlMapClient 对象配置示例
<bean id=" sqlmapClient_00001" class="org.springframework.orm.ibatis.SqlMapClient
FactoryBean">
<property name="configLocation" value="classpath:/sqlmap/db2/sql-map-config.xml"/>
<property name="dataSource">
<ref local=" datasource_00001"/>
</property>
</bean>
重写 SqlMapClient 接口的实现类 RoutingSqlMapClient
生成了 SqlMapClient 对象后,我们还要创建一个 RoutingSqlMapClient 的实现类用来重写相应的 SqlMapClient 接口方法。RoutingSqlMapClient 将创建一个 Map 变量去承接上文生成的 SqlMapClient 实现对象的 Map 列表,然后根据关键字来判断用哪个实现对象来动态的重写 RoutingSqlMapClient 类。RoutingSqlMapClient 使用变量 targetSqlMapClients 来接收 SqlMapClient 对象列表。
清单 4. RoutingSqlMapClient 类的代码片段
public class RoutingSqlMapClient implements SqlMapClient {
private Map<String, SqlMapClient> targetSqlMapClients;
public void flushDataCache()
{
targetSqlMapClients.get(getDSType()).flushDataCache();
}
public SqlMapSession getSession()
{
return targetSqlMapClients.get(getDSType()).getSession();
}
public int delete(String id, Object parameterObject) throws SQLException
{
return targetSqlMapClients.get(getDSType()).delete(id,parameterObject);
}
public Object insert(String id, Object parameterObject) throws SQLException
{
return targetSqlMapClients.get(getDSType()).insert(id,parameterObject);
}
public List queryForList(String id, Object parameterObject) throws SQLException {
return targetSqlMapClients.get(getDSType()).queryForList(id,parameterObject);
}
……
}
创建继承 SqlMapClientDaoSupport 的 DAO 类
我们选择使用 RoutingSqlMapClient 重写 SqlMapClient 的实现方法,而不是将 SqlMapClient 实现对象直接注入到对应 DAO 中的原因是:一个 DAO 类有可能对应多个数据源,如果将只包含一个数据源的 SqlMapClient 实现对象直接注入 DAO,那将严重限制 DAO 的可重用性。因此我们将整个 SqlMapClient 实现对象的列表装载入 RoutingSqlMapClient 类,在逻辑层定义使用哪一个 SqlMapClient 对象对 RoutingSqlMapClient 进行重写,持久层的 DAO 架构如下图所示:
图 3. 持久层 DAO 架构图(查看大图)
DAO 实体类继承 SqlMapClientDaoSupport 并实现相应不同的接口。如图所示,不同的接口对应不同的上层逻辑,而实现其逻辑的 DAO 实现类引用了不同的数据源和 sqlmap-config.xml,这些数据源和 XML 定义在 SqlMapClient 对象内,当我们调用持久层 DAO 类对数据库进行操作时需要先调用 RoutingSqlMapClient 内的 setDSType() 方法来确定使用哪个数据源,并使用对应的 SqlMapClient 实现对象对 RoutingSqlMapClient 进行重写,这样就可以把对应此数据源的 SqlMapClient 以 RoutingSqlMapClient 对象的形式传入到 DAO 内,实现多数据源并存的结构了。
支持动态更新的多数据源持久层开发完毕后,还应该为用户开发一套 UI 组件来使用户能够对数据源信息进行更新和维护。而每次用户更新完毕都要调用 SqlMapClientFactory 类的 init 方法,来重新生成 SqlMapClient 的 XML 配置文件,这样就可以不重新启动服务器而实现数据源的动态更新和添加了。
回页首
总结
本文描述了,可动态更新的多数据源持久层系统的一种实现方式,对于开发类似项目的开发者有一定的借鉴作用。但是由于本文的主要目的是阐述一种理念方法而不是具体实现,所以一些相关技术及具体实现没有写出,但开发者可以根据本文的思路选用自己喜欢的方式来进行实现,此外对于一些名词和 iBATIS 及 Spring 的功能没有予以详细介绍,建议对 iBATIS 架构不熟的读者能够自行参考其它教程。本文选用 Spring+iBATIS 框架仅作为示例,但仅仅是建议使用,不对使用结果和效果做任何保证。(本文内容仅代表作者个人观点)
- 大小: 10.5 KB
- 大小: 12.5 KB
- 大小: 39.4 KB
分享到:
相关推荐
Spring是一个全面的后端开发框架,提供了依赖注入、AOP(面向切面编程)、事务管理等特性,而iBatis则是一个优秀的持久层框架,它将SQL语句与Java代码分离,使得数据库操作更加灵活和易于维护。将两者整合可以实现松...
在SpringMVC+Spring+Ibatis的架构中,多数据源配置是一项重要特性。这允许应用连接到多个数据库,根据业务需求选择合适的数据库进行操作。在Spring中,可以通过DataSourceRouter或AbstractRoutingDataSource实现动态...
在IT行业中,Spring和iBatis是两个非常重要的开源框架,它们分别专注于依赖注入(DI)和持久层操作。Spring作为一个全面的Java企业级应用开发框架,提供了强大的IOC(Inversion of Control)容器,用于管理对象的...
2. **配置Spring**:接下来,需要在Spring的配置文件中定义iBATIS的SqlMapClient或SqlSessionFactory Bean,并配置数据源、事务管理器等相关属性。 3. **定义映射文件**:iBATIS的核心在于定义SQL映射文件,这些...
给定的XML配置文件展示了如何在Spring中配置ibatis数据源以及ibatis事务管理器。首先,注释掉的`BasicDataSource`部分是用来配置数据源的,这里没有启用,而是选择了使用JNDI数据源。实际生产环境中,通常会使用...
而iBatis(现为MyBatis)则是一个轻量级的持久层框架,它简化了SQL操作,将Java代码与SQL语句分离,使得数据库操作更为灵活和便捷。 在这个实例中,我们首先会看到一个标准的开发目录结构,这通常包括以下几个部分...
而 iBATIS 是一个持久层框架,它简化了数据库操作,将 SQL 语句与 Java 代码分离,提供了灵活的数据访问接口。 在整合 Spring 和 iBATIS 进行项目开发时,主要涉及以下几个关键知识点: 1. **依赖注入 (Dependency...
iBatis是另一种轻量级的持久层框架,它将SQL与Java代码分离,使得数据库操作更为灵活和可控。在本系统中,iBatis作为数据访问层,负责与数据库的交互。开发者可以编写自定义的SQL语句,直接映射到Java对象,减少了对...
在Java开发领域,Spring框架以其强大的依赖注入和面向切面编程能力被广泛应用,而iBatis作为一个轻量级的持久层框架,以其灵活的SQL映射机制受到开发者喜爱。将两者整合,可以充分利用Spring的管理能力,简化数据库...
在IT行业中,Spring框架和iBatis持久层框架的整合是一个常见的应用场景,旨在提供更加灵活且高效的数据库操作。"spring-ibatis"项目的核心目标就是将Spring的依赖注入特性和iBatis的数据访问能力结合起来,使得开发...
Spring整合iBatis是将流行的Java持久层框架iBatis与Spring框架集成,以实现更高效、更灵活的数据库操作。这种整合使得开发者可以利用Spring的依赖注入(DI)和管理事务的能力,同时享受iBatis提供的SQL映射功能。在...
而iBatis作为一个持久层框架,简化了数据库操作,将SQL与Java代码分离。 【描述】: 虽然描述部分为空,但我们可以假设这篇博文详细介绍了如何配置这三个组件。在实际开发中,首先会创建一个新的Maven项目,并在`...
而iBatis则是一个轻量级的持久层框架,它将SQL语句与Java代码分离,让开发者能够更自由地编写SQL,提高数据库操作的灵活性。 在"spring-ibatis"的集成中,我们通常会做以下几步配置: 1. **添加依赖**:在项目构建...
Spring是一个全面的Java应用程序框架,提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性,而iBatis(现为MyBatis)则是一个轻量级的持久层框架,它简化了SQL操作,将SQL语句与Java代码分离。...
Struts2、Spring和iBatis是Java Web开发中常用的三大框架,它们分别负责MVC模式中的Action层、业务逻辑层和服务数据访问层。本文将详细介绍这三个框架如何整合,以及在实际项目中如何运用。 首先,Struts2作为表现...
4. **数据源(DataSource)**:iBATIS 需要连接到数据库,因此需要配置数据源,可以是 JDBC 数据源或其他连接池实现。 5. **MyBatis**:iBATIS 后续发展为 MyBatis,增加了更多功能,如支持注解、更丰富的动态 SQL ...
WebWork 是一个MVC(Model-View-Controller)框架,Spring 是一个全面的后端开发框架,而 iBATIS 是一个持久层框架,用于简化数据库操作。以下是对这些框架的详细解释和它们如何协同工作的概述。 **WebWork**: ...
iBATIS是一个持久层框架,它解决了Java应用程序与数据库之间的交互问题。它将SQL语句直接写在XML配置文件中,提供了动态SQL的能力,使得数据库操作更加灵活。iBATIS与Spring结合,可以利用Spring的DI特性管理...