`

面向 Java 开发人员的 db4o 指南:第 7 部分:事务、分布和安全性

    博客分类:
  • Java
阅读更多
通过直接在面向对象的数据库(如 db4o)中存储对象,Java™ 开发人员可以获得很多好处。如果 OODBMS 缺乏对事务的支持或不能在分布式环境中使用数据(并保证其安全性),您可能不会过多地使用它。在面向 Java 开发人员的 db4o 指南 的最后一期中,Ted Neward 展示了如何使用 db4o 处理 3 个与 Java 企业开发密切相关的问题:事务、分布式数据管理和 Web 应用程序安全性。

 

关于本系列
信息存储和检索作为同义语伴随 RDBMS 已经有 10 余年了,但现在情况有所改变。Java 开发人员为所谓的对象关系型阻抗失配而沮丧,也不再有耐心去尝试解决这个问题。加上可行替代方案的出现,就导致了人们对对象持久性和检索的兴趣的复苏。 面向 Java 开发人员的 db4o 指南 是对开放源码数据库 db4o 的详尽介绍,db4o 可以充分利用当前的面向对象的语言、系统和理念。要实践本系列的示例,需要下载 db4o,可以从 db4o 主页 下载获得。

在本系 列中,我介绍了使用 db4o 进行面向对象数据管理的基本要素。但是还有一点没有讨论,那就是如何在 Web 应用程序中使用 OODBMS,以及与在 Swing 或 SWT 中使用 OODBMS 有何不同。可以说,我忽略的这些内容是 Java(或 .NET)开发人员不能忽略的。

一定程度上,我应该关注 OODBMS 最引人注目的功能:面向对象数据的存储、操作和检索。同样地,OODBMS 供应商也试图实现诸如事务管理和安全性之类的核心功能。这些功能与各种 RDBMS 的相应功能类似,并且具有类似的选项范围。

面向 Java 开发人员的 db4o 指南 的最后一期中,我将要讨论任何数据存储系统(面向对象的、关系的,等等)都应该拥有的 3 个特性。了解 db4o 如何支持应用程序安全性、分布和事务。

多客户端连接

迄 今为止,我为本系列编写的代码都假设数据库只有一个客户端。换句话说,只会为数据库创建一个逻辑连接,所有的交互都通过该连接来完成。对于要访问配置数据 库或逻辑存储系统的 Swing 或 SWT 应用程序,这是一个非常合理的假设。但是对于 Web 应用程序,即使是所有的存储都是在 Web 表示层完成的程序,这个假设也不太符合实际。

在 db4o 系统中,打开第二个数据库逻辑连接非常简单,即使当数据库驻留在本地磁盘上时也是如此。我只需要首先添加一个调用创建 ObjectServer ,并从 ObjectServer 获取 ObjectContainer 对象。让 ObjectServer 在端口 0 上监听,这样会告诉它以 “嵌入式” 模式运行,并且在进行下一个探察测试时不会打开(或威胁)实际的 TCP/IP 端口。


清单 1. 嵌入式连接

                    
@Test public void letsTryMultipleEmbeddedClientConnections()
    {
        ObjectServer server = Db4o.openServer("persons.data", 0);
        
        try
        {
            ObjectContainer client1 = server.openClient();
            Employee ted1 = (Employee)
                client1.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next();
            System.out.println("client1 found ted: " + ted1);
            
            ObjectContainer client2 = server.openClient();
            Employee ted2 = (Employee)
                client2.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next();
            System.out.println("client2 found ted: " + ted2);
            
            ted1.setTitle("Lord and Most High Guru");
            client1.set(ted1);
            System.out.println("set(ted1)");

            System.out.println("client1 found ted1: " +
                client1.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());

            System.out.println("client2 found ted2: " + 
                client2.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());
                
            client1.commit();
            System.out.println("client1.commit()");

            System.out.println("client1 found ted1: " +
                client1.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());

            System.out.println("client2 found ted2: " + 
                client2.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());
                
            client2.ext().refresh(ted2, 1);
            System.out.println("After client2.refresh()");
            System.out.println("client2 found ted2: " + 
                client2.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());
            
            client1.close();
            client2.close();
        }
        finally
        {
            server.close();
        }
    }

 

刷新对象视图

注意,当运行该测试时,我向测试代码中添加了一些输出行。需要对发生的行为进行跟踪,因为 db4o 需要一直保持对打开对象的引用。还应该确保了解内存中对象的更新是在什么时候和什么位置 “传递” 给第二个客户端的。

适用用例:当我进行 set(ted1) 调用时,db4o 系统修改其内部状态,以了解 ted1 是脏对象并需要更新。但是,在使用 ObjectContainer 上的 commit() 方法提交显式事务之前,它不会进行实际更新。此时,数据被写入磁盘,但是跟磁盘上的数据相比,内存中 client2 的对象视图仍然是陈旧的(回顾一下探察测试的输出。在阅读本系列时,您已经 在流览器旁边的控制台窗口运行了该代码)。

改进方法很简单:client2 使用 extension 对象上的 refresh() 方法刷新它在内存中的对象图视图,extension 对象由 ext() 返回。注意激活深度是一个重要因素:当刷新对象时,您希望 db4o 深入到对象图的哪个深度?在本例中,逐步降低深度(single step down)就可以检索修改的 Employee 了,但是对于不同的情形,应该重新考虑。

一旦其对象视图被刷新,client2 就会了解到所做的更改。快速查询将会显示出公司领导的新头衔。

 




 

跨多个进程

大多数时候,多个客户端不会只具有单个进程,而是可以跨多个进程。例如,在典型的客户机-服务器风格中,将有多个客户机而不是一个 servlet 容器与单个服务器会话。在 db4o 中实现此功能的方法与 清单 1 大体相同。惟一的区别在于需要用一个非 0 的端口号来打开服务器。该端口号表示服务器监听的 TCP/IP 端口。所有基于 TCP/IP 的通信都是这样,当进行连接时,客户端必须指定主机名和端口。

 



 

安全性

自然地,当涉及一个端口时,就得考虑安全性,因为您不能允许 “所有人” 连接服务器并进行查询。在传统的 RDBMS 实现中,供应商提供了一个强大的安全模型,当数据库连接打开时,要访问数据库实例的部分或所有内容,必须向数据库发送凭证(用户名和密码)。

db4o 实现也是这样,至少在效果上是一样的。但是 db4o 数据库实例创建者设置授权安全策略的方法与常见 RDBMS 场景有很大区别,如清单 2 所示:


清单 2. 和其他人进行通信

                    
@Test public void letsTryMultipleNetworkClientConnections()
    {
        ObjectServer server = Db4o.openServer("persons.data", 2771);
        server.grantAccess("client1", "password");
        server.grantAccess("client2", "password");
            // Yes, "password" is a bad password. Don't do this in production
            // code. I get to do it only because I have a special Pedagogical
            // Code License from Sun Microsystems. And you don't. So don't do
            // this. Don't make me come over there. I'm serious. 
            // Fuggedaboutit. Never. Not ever. Capice?
        
        try
        {
            ObjectContainer client1 = 
                server.openClient("localhost", 2771, "client1", "password");
            
            ObjectContainer client2 = 
                server.openClient("localhost", 2771, "client1", "password");
                
            Employee ted1 = (Employee)
                client1.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next();
            System.out.println("client1 found ted: " + ted1);
                
            Employee ted2 = (Employee)
                client2.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next();
            System.out.println("client2 found ted: " + ted2);
            
            ted1.setTitle("Lord and Most High Guru");
            client1.set(ted1);
            System.out.println("set(ted1)");

            System.out.println("client1 found ted1: " +
                client1.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());

            System.out.println("client2 found ted2: " + 
                client2.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());
                
            client1.commit();
            System.out.println("client1.commit()");

            System.out.println("client1 found ted1: " +
                client1.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());

            System.out.println("client2 found ted2: " + 
                client2.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());
                
            client2.ext().refresh(ted2, 1);
            System.out.println("After client2.refresh()");
            System.out.println("client2 found ted2: " + 
                client2.get(
                    new Employee("Ted", "Neward", null, null, 0, null))
                .next());
            
            client1.close();
            client2.close();
        }
        finally
        {
            server.close();
        }
    }

 

要在 db4o 中定义访问控制,只需使用 grantAccess() 方法,它授权对整个数据库实例的访问。这种方法简化了安全设置场景,但是这样一来就无法使用最小特权原则了,因此该方法既有优点也有缺点。

最小特权原则

和许多安全思想一样,最小特权原则 的原理很简单,但是有时难于在实践中实现。该原则规定给定用户或代码体应该被授予能完成所分配任务的最少权限,不能拥有多余的特权(显然也不能缺少必要的特权)。例如,在一个 RDBMS 场景中,访问 RDBMS 的代码应该只对它访问的表拥有基本的 SELECT/INSERT/UPDATE/DELETE 权限 ,而不能超出这些权限。这样,即使代码中包含 SQL 注入攻击程序,它也不能执行注入攻击,因为它没有足够的数据库访问权限。

目前 db4o 还不支持更加粒度化级别的解决方式,其他 OODBMS 系统可能更加灵活。您应该确保只使用了最小数量的安全性凭证。如果不能限制登录需要使用的资源,那么至少可以限制系统访问原则的数量。

加密格式

分布式系统的安全性问题 — 尤其是 Fourth Fallacy of Enterprise Computing(参考 参考资料 中的 Effective Enterprise Java )— 说明,不能认为只有监听网络通信量的人或代码才是可信的。这意味着您必须确保在网络中传输的数据不是明文和二进制形式(如果使用的二进制形式的格式众所周知,那么它和明文形式是相同的)。

关心安全性的开发人员也会关心存储在 db4o 文件中的数据,因为文件 “仅仅是文件”,因此打开文件和阅读其中的内容会将文件暴露给攻击者(关系数据库也存在着这类问题)。

解 决方案是对文件进行加密,这在 db4o 中比较简单。对于大多数场景,db4o 的默认加密模式 eXtended Tiny Encryption Algorithm (XTEA) 对暴露给攻击者的数据进行模糊化。对于其他实例,db4o 提供了一个定制加密 “技巧”,支持使用第三方加密提供程序(不要定义自己的加密格式,除非您可以编写出论文挑战既有标准,并受到全世界密码学家和数学家的关注,而且可以在主 流安全会议上进行辩护。如果达到了这些要求,您可以 考虑使用它,毕竟,没有被发现并不意味着不存在)。

保护数据

保护有线形式(wire-format)的数据传输比较困难,因为 db4o 6.3 及以前的版本都没有提供工具跨安全的传输线(比如通过 SecureSocket 传输的 SSL)进行通信。这意味着任何敏感数据都必须以加密的方式传输,这暗示着对象本身应该包含某种形式的加密(如果 db4o 可以直接实现这一功能就太好了;在撰写本文的时候,db4o 6.4 版已经计划支持将 SocketFactory 传递到 openServer 调用,因此您可以使用 SecureSocket 连接取代完全开放的 Socket 连接)。

注意可以使用定制编组程序 通过 “横切(cross-cutting)” 方式进行传递以保护数据。顾名思义,这使您能够控制数据的打包(和解包)方式,以在线路上进行传输。这种方法与通过 Externalizable 接口定制串行化非常相似:编写一个实现 ObjectMarshaller 接口的类,实现 readFields()writeFields() 方法,然后告诉 db4o 系统对特定类的对象使用定制的编组程序,具体方法是在目标类的 ObjectClass 上调用 marshallWith() 。完整的代码如下:

Db4o.configure().objectClass(Item.class).marshallWith(customMarshaller);

 

这样做不会保护整个线路 — 攻击者仍然可以查看保存的对象类型 — 但是它会在网络上进行节点到节点传输时阻止数据被别人查看。

当 db4o 选项 “嵌入式和客户机/服务器” 不能满足需要时,比如将数据存储到特定的文件格式或非传统的数据存储资源中,db4o 库允许创建 IoAdaptor 的一个子类,该类是 db4o 在存储对象时写入数据的关键抽象。这让存储具有一定程度的灵活性,而大多数 RDBMS 系统都不具有这种灵活性。

 




 

结束语

关 于 OODBMs 和 db4o,还有大量内容值得讨论和研究,但是我已经完成了预定目标并决定暂时结束本系列。我相信我展示了一个关于 db4o 和面向对象数据管理的良好示例,并从 Java 开发人员的角度介绍了 RDBMS 不同于 OODBMS 的特性。我展示了如何使用 db4o 轻松地跟踪关联(track association);db4o 如何获得作为数据库优秀概念的继承性;db4o 如何使用定义对象的原生编程语言简化对象检索。

我也讨论了 OODBMS 的一些不足,以及 db4o 与 RDBMS 都存在的缺陷,比如在处理客户机-服务器网络中的 “往返传输” 时出现的性能问题。

只 要跟随本系列的示例并试用了其中的代码,就会获得使用任何 OODBMS 系统(不只是 db4o)的必备技巧。您可以尝试将所学知识应用到 Cache' 或 Versant 上。大多数 OODBMS 都遵循相同的基本编码约定和惯用表达式,而且实际上 db4o 对原生查询的支持已逐渐成为一种标准,使该特性成为所有 OODBMS 的一部分。

希望您能在本系列中找到所需的内容,并已准备好在您自己的项目中使用 OODBMS。这将是一种轻松的体验,不用担心关系模式和所有相关的内容。因此,请放松心情:试验、实现、在实践中体验乐趣,不要忘了来信告诉我您的经验(或者给我发送电子邮件)。

分享到:
评论

相关推荐

    面向 Java 开发人员的 db4o 指南: 第 3 部分:db4o 中的数据库重构

    db4o将Java对象直接持久化到磁盘,通过对象的引用关系来处理数据,简化了开发过程,特别是对于面向对象的设计模式来说,可以更好地保持数据的一致性和完整性。 ### 2. db4o的API介绍 db4o提供了一套直观的API来...

    面向 Java 开发人员的 db4o 指南 结构化对象和集合

    面向Java开发人员的db4o指南主要关注如何利用db4o进行结构化对象和集合的管理,从而提高开发效率和数据存储的灵活性。 **对象数据库** 与传统的关系型数据库(RDBMS)不同,对象数据库直接支持面向对象编程模型。在...

    面向Java开发人员的db4o指南db4o中的数据库重构.doc

    面向Java开发人员的db4o指南db4o中的数据库重构

    db4o使用指南

    "db4o 使用指南" db4o 是一个开源的面向对象数据库,能够轻松地将 Java 对象持久化到数据库中。本文将详细介绍 db4o 的安装、启动、查询方式、对象持久化、数据库文件结构、主要包结构等知识点。 一、db4o 安装和...

    db4o开发指南和各种实例

    **八、事务、分布和安全性** db4o支持ACID事务,确保数据的原子性、一致性、隔离性和持久性。分布式数据库功能使得多台机器上的db4o实例可以协同工作,提高系统的可用性和扩展性。在安全性方面,db4o提供了访问控制...

    db4o 权威指南

    《db4o 权威指南》是一本深入探讨db4o这一开源面向对象数据库系统的专业书籍,对于Java开发者来说尤其有价值。db4o是Database for Objects的缩写,它允许开发者以自然、直观的方式存储和检索Java对象,无需编写SQL...

    DB4O Java开发应用

    同时,DB4O支持事务管理和版本控制,以确保数据的一致性和可恢复性。 - 完整的全源码和注解:为了深入理解DB4O的工作原理和最佳实践,开发者通常需要参考完整的示例代码和详细的注释。这些资源可以帮助你更好地了解...

    db4o中文指南

    db4o是一个专为Java和.NET开发者设计的开源、轻量级的纯面向对象数据库引擎,提供了一种简单易用的方式来实现对象持久化。这款数据库引擎已被验证具备优秀的性能,根据描述中的基准测试,db4o在与传统持久化方案的...

    java数据库(db4o)

    Java数据库db4o,全称为“Database for Objects”,是一款开源的对象数据库系统,专门设计用于Java和.NET平台。它提供了一种直接在对象模型上进行数据操作的方式,无需传统的ORM(对象关系映射)层,简化了开发过程...

    db4o for java

    7. **事务支持**:db4o提供了ACID(原子性、一致性、隔离性和持久性)事务,确保了数据的一致性和完整性。 8. **事件驱动**:db4o支持对象生命周期事件,如对象插入、更新和删除时触发自定义的事件处理器,这为实现...

    db4o8.0以及db4o中文指南

    2. **事务支持**:提供了更强大的事务管理,确保数据的一致性和完整性,支持ACID(原子性、一致性、隔离性、持久性)原则。 3. **持久化策略**:新增了多种持久化策略,如延迟加载(Lazy Loading)、透明激活...

    Db4o的简单操作项目

    Db4o,全称为“Database for Objects”,是一个开源...尽管Db4o已经停止了官方支持,但它的设计理念和模式对于理解对象数据库的概念仍然很有价值,特别是对于那些希望避开传统关系型数据库复杂性的小型项目或原型开发。

    db4o-5.0-tutorial-java帮助

    描述:这份资料是关于db4o数据库的使用教程,特别针对Java开发人员。db4o是一款开源的对象数据库,支持Java、.NET以及Mono平台。该教程旨在帮助用户快速上手db4o,并在开发过程中提供可靠的支持。 ### 一、db4o概述...

    DB4O_java

    DB4O(Database for Objects)是一款开源的对象数据库管理系统(Object-Relational Mapping,ORM),它专为Java平台设计,提供了一种将对象直接持久化的解决方案,免去了传统的对象关系映射的复杂性。DB4O的目标是...

    db4o6.4-java

    - **兼容性**:db4o可能与不同的JVM版本和Java库存在兼容性问题,确保你的开发环境与db4o版本匹配。 - **性能优化**:尽管db4o提供了许多便利,但其性能可能不如优化过的SQL数据库。在性能敏感的场景下,需要评估和...

    db4o-7.2-java

    **db4o-7.2-java** 是一个针对Java平台的开源对象数据库系统,它将传统的关系型数据库理念与面向对象编程相结合,为开发者提供了一种高效、灵活的数据存储解决方案。db4o允许开发者直接存取Java对象,而无需通过SQL...

    db4o-8.0-java

    **db4o(Database for Objects)** 是一个开源的对象数据库管理系统(Object-Relational Mapping,ORM),它允许开发者直接在Java或.NET平台上存储和检索Java对象或.NET对象,无需进行SQL查询或者映射过程。db4o的...

    db4o-8.0.276.16149-java.rar

    对于Java开发者而言,能够在Eclipse这样的流行开发环境中集成db4o,可以极大地提升开发效率和项目的可维护性。 在压缩包内的"db4o-8.0.276.16149-java"可能包含了以下组件: 1. **db4o JAR文件**:这是db4o的核心库...

    DB4O面向对象数据库使用指南

    DB4O面向对象数据库使用指南

    开源面向对象数据库 db4o 之旅

    该资源为 db4o 之旅 系列文章: ...3.介绍面向对象数据库 db4o 的修改和删除,并对其中出现的问题进行细致分析,引入了“更新深度(update depth)”这一重要概念。 最后更新于2006 年 12 月 14 日 另外再推荐一个站点 ...

Global site tag (gtag.js) - Google Analytics