成都心情

  BlogJava :: 首页 ::  :: 联系 :: 聚合  :: 管理 ::
  98 随笔 :: 2 文章 :: 501 评论 :: 1 Trackbacks

IBM DeveloperWorks(IBM DW) 版权所有!引用、转贴本文应注明本文来自 IBM DW。

前言

在开源面向对象数据库 db4o 之旅 系列文章的第 1 部分:初识 db4o 中,作者介绍了 db4o 的历史和现状、应用领域、以及和 ORM 等的比较;在第 2 部分:db4o 查询方式 中 , 作者介绍了 db4o 的三种不同的查询方式:QBE、SODA 以及 Native Queries,并分别通过这三种不同的途径实现了两个关联对象的查询;在第 3 部分:深入 db4o 中,作者介绍了 db4o 的修改和删除,引入了“更新深度 (update depth)”这一重要概念。

从本系列第 3 部分到现在的第 4 部分,中间经历了漫长的时间。db4o 本身也在进步,2008 年 12 月,对象数据库领导厂商 Versant 公司收购了 db4o 及其开发团队,这次收购为 db4o 注入了新的活力。前面我们介绍了 db4o 中如何对对象进行更新以及删除操作,在本文中我将向您介绍在 db4o 中如何与关系型数据库 (RDBMS) 进行同步。


dRS 应用范围

dRS 充分利用了 Hibernate 的优势,可实现 db4o 到 RDBMS、db4o 到 db4o、以及 RDBMS 到 RDBMS 的双向或单向的数据同步。

图 1 所示,我们来设想这样的场景:一位名叫“张三”的车主买了几辆车,随即去主管部门办牌照,办证人员把数据采集进部署了 db4o 的手持设备(可能是基于 Android OS 的平板电脑);数据采集完后直接从手持设备通过无线、有线连接同步到桌面应用程序、应用服务器 (Hibernate/RDBMS) 中存档。正确!无需再编写额外的代码来关心对象如何写入 RDBMS。


图 1. dRS 模型
dRS 模型


下载并安装 dRS

进入 db4o 的 下载页面,可以看到最新的 for java 稳定版本都已经是 7.4 了,这次需要在下载的是 db4o Replication System(dRS) for Java,为了能顺利运行本文的例子,请一并下载 db4o 的 7.4 版。在 Eclipse 中建立一个 Java 项目,把 dRS lib 下的 jar 包都导入进去。

本系列前几篇文章提到的 ObjectManager 工具已经升级为 ObjectManagerEnterprise(OME),作为 Eclipse 插件运行,在 db4o 7.4 版 ZIP 压缩包中的”\ome\ObjectManagerEnterprise-Java-7.4.0.zip”路径下可找到。


装载数据表

本系列前几篇文章中的 AutoInfo 和 People 还可以沿用,只是略微做了调整,由于 dRS 需要 Hibernate 的支持,故还要配置 Hibernate 映射文件。需要注意的是,映射文件中必须设置名为”typed_id”的主键字段,”type”必须是”long”,而”class”必须是”native”,这样做是为了 RDBMS 中能够维护对象间的关系以及 dRS 自身的管理,稍后会看到”typed_id”是如何发挥作用的;另外,"default-cascade"属性必须设置为"save-update",如果设置成”delete”了,dRS 将不响应删除操作。相应的业务对象和映射文件请到 下载 部分获取。

现在类和映射文件都写好了,还要配置最重要的 Hibernate 配置文件。要注意的是"hibernate.connection.pool_size"属性只需设置为"1",因为 dRS 到 RDBMS 只需要一个连接,多了也没作用;"hibernate.jdbc.batch_size"设置为"0"是为了调试方便,在实际使用的时候还是设置一下较好;"hibernate.hbm2ddl.auto"一定要设置为”update”,这是因为 dRS 在向 RDBMS 装载数据表的时候会创建额外的元数据表,如果设置为"validate",那么就需要自己手工去建这些表了,否则会报错。


清单 1. Hibernate 配置文件
            <hibernate-configuration>
            <session-factory>
            <property name="hibernate.connection.driver_class">
            oracle.jdbc.driver.OracleDriver</property>
            <property name="hibernate.connection.url">
            jdbc:oracle:thin:@192.168.1.173:1521:ora10g</property>
            <property name="hibernate.connection.username">test</property>
            <property name="hibernate.connection.password">test</property>
            <property name="hibernate.connection.pool_size">1</property>
            <property name="hibernate.dialect">
            org.hibernate.dialect.OracleDialect</property>
            <property name="hibernate.show_sql">false</property>
            <property name="hibernate.hbm2ddl.auto">update</property>
            <property name="hibernate.jdbc.batch_size">0</property>
            <mapping resource="bo/People.hbm.xml"/>
            <mapping resource="bo/AutoInfo.hbm.xml"/>
            </session-factory>
            </hibernate-configuration>
            

万事具备,现在开始编写装载数据表的代码吧,请看 清单 2 中的代码,涉及到 dRS 的其实只有两行,由于 People 和 AutoInfo 对象之间是 one-to-many 的关系,故只需要关注 People。


清单 2. CreateTable 类
            public class CreateTable {
            public static void main(String args[]){
            Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
            ReplicationConfigurator.configure(cfg);
            SessionFactory sessionFactory = cfg.buildSessionFactory();
            Session session = sessionFactory.openSession();
            ReplicationConfigurator.install(session, cfg);
            session.createCriteria(People.class);
            session.close();
            sessionFactory.close();
            }
            }
            

如果不出意外,运行完上面的代码后,相应的数据库表也就被建立好了。如 图 2所示,除了 people 和 autoinfo 表以外,还有三个 dRS 的元数据表。


图 2. Oracle 数据库表
Oracle 数据库表


从 db4o 到 RDBMS 的复制

请看 清单 3中的代码,在”main”方法中,我构造了一个 db4o 配置类,并设置了 UUIDs 和 VersionNumbers 生成策略。这里的 UUID 是为了标识 db4o 中存储的数据,而 VersionNubmers 则是为了 dRS 在同步时维护数据状态,所以必须进行设置。


清单 3. ReplicationExample 类
            public class ReplicationExample {
            public static void main(String args[]){
            com.db4o.config.Configuration db4oconf = Db4o.newConfiguration();
            db4oconf.generateUUIDs(ConfigScope.GLOBALLY);
            db4oconf.generateVersionNumbers(ConfigScope.GLOBALLY);
            createReplication(db4oconf);
            }
            private static void createReplication(com.db4o.config.Configuration db4oconf){
            ObjectContainer odb = Db4o.openFile(db4oconf, "auto.yap");
            Configuration config = new Configuration().configure("hibernate.cfg.xml");
            // 绑定 A(db4o 数据库 ) B(Oracle 数据库 ) 关系
            ReplicationSession replication = HibernateReplication.begin(odb, config);
            People peo = new People();
            peo.setAddress("成都市");
            peo.setName("张三");
            for(int i=0; i<10; i++){
            AutoInfo ai = new AutoInfo();
            ai.setLicensePlate("川 A00000"+i);
            peo.addAutoInfo(ai);
            }
            odb.store(peo);
            odb.commit();
            // 找出 A(db4o 数据库 ) 中存在的数据
            ObjectSet changed = replication.providerA().objectsChangedSinceLastReplication();
            // 复制到 Oracle 数据库
            while (changed.hasNext()){
            replication.replicate(changed.next());
            }
            replication.commit();
            replication.close();
            odb.close();
            }
            }
            

在”createReplication”方法中,通过 HibernateReplication 类的 begin(odb, config) 方法,把 db4o 和 Hibernate 的配置实例联系到一起;接下来向 db4o 中创建一个 People 对象和 10 个 AutoInfo 对象,并提交到 db4o;最后找出哪些是 db4o 中存在而 RDBMS 却没有的数据,把这些数据委托给 dRS,让 dRS 复制到 RDBMS。请注意代码注释中 A (db4o 数据库 ) B (Oracle 数据库 ) 的含义和关系。运行完代码后,可以发现 Oracle 中有了新数据,参看 图 34


图 3. people 表
people 表

图 4. autoinfo 表
autoinfo 表


从 db4o 到 RDBMS 的更新与删除

现在来看看如何进行更新和删除。注意 清单 4中的代码,在 updateOraReplication 方法中,首先通过 QBE 查询把车牌号为”川 A000001”的 AutoInfo 对象查出来,然后改成”川 B000001”提交到 db4o,随后 dRS 发现有条数据被修改,找出来之后更新到 RDBMS;同样,通过 QBE 查询把车牌号为”川 A000002”的 AutoInfo 对象查出来,删除后提交到 db4o,最后使用 ReplicationSession 实例的 replicateDeletions(AutoInfo.class) 方法来通知 dRS 对删除数据进行处理。


清单 4. updateOraReplication 方法
            private static void updateOraReplication(com.db4o.config.Configuration db4oconf){
            ObjectContainer odb = Db4o.openFile(db4oconf, "auto.yap");
            Configuration config = new Configuration().configure("hibernate.cfg.xml");
            // 绑定 A(db4o 数据库 ) B(Oracle 数据库 ) 关系
            ReplicationSession replication = HibernateReplication.begin(odb, config);
            // 更新
            AutoInfo ai = new AutoInfo();
            ai.setLicensePlate("川 A000001");
            List<AutoInfo> list = odb.queryByExample(ai);
            if(list.size() == 1){
            ai = list.get(0);
            ai.setLicensePlate("川 B000001");
            odb.store(ai);
            }
            odb.commit();
            // 找出 A(db4o 数据库 ) 中修改过的数据
            ObjectSet changed = replication.providerA().objectsChangedSinceLastReplication();
            // 更新到 Oracle 数据库
            while (changed.hasNext()){
            replication.replicate(changed.next());
            }
            // 删除
            ai = new AutoInfo();
            ai.setLicensePlate("川 A000002");
            list = odb.queryByExample(ai);
            if(list.size() == 1){
            odb.delete(list.get(0));
            }
            odb.commit();
            replication.replicateDeletions(AutoInfo.class);
            replication.commit();
            replication.close();
            odb.close();
            }
            

dRS 把更新和删除操作一并提交。运行完代码后立刻查看 autoinfo 表的变化吧。


从 RDBMS 到 db4o 的更新

dRS 支持双向数据同步,刚才我们已经看到单向是如何同步的,现在看看修改了 RDBMS 中的数据后如何反映到 db4o 里。

在继续写代码之前,讲讲前面提到的”type_id”字段,其实该字段是 dRS 在做维护的时候需要关注的。RDBMS 中有一个 dRS 自动生成的 drs_objects 表,该表维护了每条业务数据对应 db4o 中的类名、对应业务数据表的”type_id”、创建和修改时间。那么在 RDBMS 中修改了业务数据的值怎么通知 dRS 呢?答案是修改 drs_objects 表对应的修改时间,让该时间大于上次同步操作的时间,如何做?执行这样的 SQL 语句:update drs_objects t set t.modified=(select max(a.time)+1 from drs_history a) where t.typed_id=xxx,其中 xxx 代表你要修改的业务数据的”typed_id”,通过这个 SQL 语句,让我们知道了其实 dRS 记录同步操作时间是在 drs_history 表中,每次同步都会改变其中的值。

有了上面的认识接下来就好写了,首先修改 autoinfo 表中”type_id”为”454”的数据,把车牌号改为”川 D000003”,然后执行 SQL:update drs_objects t set t.modified=(select max(a.time)+1 from drs_history a) where t.typed_id=454,主动更新修改时间。


清单 5. updateDb4oReplication 方法
            private static void updateDb4oReplication(com.db4o.config.Configuration db4oconf){
            ObjectContainer odb = Db4o.openFile(db4oconf, "auto.yap");
            Configuration config = new Configuration().configure("hibernate.cfg.xml");
            // 绑定 A(db4o 数据库 ) B(Oracle 数据库 ) 关系
            ReplicationSession replication = HibernateReplication.begin(odb, config);
            // 找出 B(Oracle 数据库 ) 中修改过的数据
            ObjectSet changed = replication.providerB().objectsChangedSinceLastReplication();
            // 同步到 db4o 数据库
            while (changed.hasNext()){
            replication.replicate(changed.next());
            }
            replication.commit();
            replication.close();
            odb.close();
            }
            

运行 清单 5 中的代码,打开 OME 管理工具,可以看到刚才修改的数据已经被同步到了 db4o 中。正确,dRS 在 RDBMS 中找到了更新后的记录,而且修改时间是在上次同步之后,随即同步到 db4o 里。在理解了如何从 RDBMS 更新数据到 db4o 之后,相应的删除和新增操作也可通过类似的办法处理。


结论

通过上面的例子不难发现 dRS 使 db4o 的原生对象持久化体系能适用于所有的 Java 和 .NET 开发者,能够很好的处理和现有 RDBMS 的一致性,对于由此产生的数据冲突,dRS 也能很好的解决(请进一步参考 dRS 软件包中的开发文档)。dRS 100% 的面向对象且基于 GPL 开源授权,尤其适合敏捷企业开发和软件制造商的产品快速更替,以及大多数的移动业务环境。



下载

描述 名字 大小 下载方法
本文用到的业务对象和映射文件 bo_mapping.zip 2 KB HTTP

关于下载方法的信息


 

参考资料

学习

获得产品和技术

讨论

作者简介

Rosen Jiang 是 db4o 和 OO 的忠实 fans,是 2007、2008 年 db4o 的 dVP 获得者之一,为 Versant db4o 在中国的推广作出了卓越贡献。

Tiger Lau 长期致力于 odbms 的研究和应用。

IBM DeveloperWorks(IBM DW) 版权所有!引用、转贴本文应注明本文来自 IBM DW。
posted on 2010-07-09 10:19 Rosen 阅读(4279) 评论(9)  编辑  收藏 所属分类: Versant db4o 中文项目

评论

# re: 开源面向对象数据库 db4o 之旅: 使用 dRS “db4o 之旅(四)” 2010-07-09 12:57 t
所有对象都保存在一个文件?数据量很大的话读取文件很慢  回复  更多评论
  

# re: 开源面向对象数据库 db4o 之旅: 使用 dRS “db4o 之旅(四)” 2010-07-09 13:10 Rosen
@t
需要根据自己的策略调整(例如分库),最好是亲自测试一把 -:)
PS:最近NoSQL成风,但是就我关注了一些NoSQL的实现来说,都是各有优势,侧重点不同。而我也认为oodb也应该算是NoSQL阵营中的一员(希望这不是在给自己贴金),对于oodb来说,我认为是一种比较均衡的实现,ACID、性能、复杂查询、CAP(有待具体研究 目前没有文献)。  回复  更多评论
  

# re: 开源面向对象数据库 db4o 之旅: 使用 dRS “db4o 之旅(四)” 2010-07-09 13:44 t
@Rosen
NoSQL也不是什么高级东西,谈不上贴金,但是NoSQL就是为了大数据量而生的,如果oodb不是原生支持大数据量的话,应用范围只是有限的
  回复  更多评论
  

# re: 开源面向对象数据库 db4o 之旅: 使用 dRS “db4o 之旅(四)” 2010-07-09 13:52 Rosen
@t
对于db4o这个开源产品来说,海量数据有些问题,因为它的定位就是嵌入式(移动设备、网络设备等)或独立运行软件(编辑软件、杀软等)。如果是海量,需要更高级别的oodb才行,例如刚才提到的Versant企业版。  回复  更多评论
  

# re: 开源面向对象数据库 db4o 之旅: 使用 dRS “db4o 之旅(四)” 2010-07-09 13:57 @joe
从ibm网站上搞的帖子吧.....  回复  更多评论
  

# re: 开源面向对象数据库 db4o 之旅: 使用 dRS “db4o 之旅(四)” 2010-07-09 14:02 Rosen
@@joe
这.......的确也是我的稿子,只是需要声明版权,然后我就直接粘过来了,所以很多链接还是IBM DW的。  回复  更多评论
  

# re: 开源面向对象数据库 db4o 之旅: 使用 dRS “db4o 之旅(四)” 2010-08-16 17:55 Lzz
叽里呱啦  回复  更多评论
  

# re: 开源面向对象数据库 db4o 之旅: 使用 dRS “db4o 之旅(四)” 2014-06-23 17:31 java论坛
谢谢分享,真不错  回复  更多评论
  

# re: 开源面向对象数据库 db4o 之旅: 使用 dRS “db4o 之旅(四)” 2014-08-01 09:39 corplib.com
.。。。。。。。。。。。。。。。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: