1.3 Persistence layers and alternatives
In a medium- or large-sized application, it usually makes sense to organize classes by concern
(这个by concern写的不错呀!). Persistence is one concern; others include presentation, workflow,and business logic. A typical object-oriented architecture includes layers of code that represent the concerns. It’s normal and certainly best practice to group all classes and components responsible for persistence into a separate persistence layer in a layered system architecture.
In this section, we first look at the layers of this type of architecture and why we use them. After that, we focus on the layer we’re most interested in—the persistence layer—and some of the ways it can be implemented.
1.3.1 Layered architecture
A layered architecture defines interfaces between code that implements the various concerns, allowing changes to be made to the way one concern is implemented without significant disruption to code in the other layers. Layering also determines the kinds of interlayer dependencies that occur. The rules are as follows:
■ Layers communicate from top to bottom. A layer is dependent only on the layer directly below it.
■ Each layer is unaware of any other layers except for the layer just below it.
Different systems group concerns differently, so they define different layers. A typical, proven, high-level application architecture uses three layers: one each for presentation, business logic, and persistence, as shown in figure 1.4.
Let’s take a closer look at the layers and elements in the diagram
(见附件):
■ Presentation layer—The user interface logic is topmost. Code responsible for the presentation and control of page and screen navigation is in the presentation layer.
■ Business layer—The exact form of the next layer varies widely between applications. It’s generally agreed, however, that the business layer is responsible for implementing any business rules or system requirements that would be understood by users as part of the problem domain. This layer usually includes some kind of controlling component—code that knows when to invoke which business rule. In some systems, this layer has its own internal representation of the business domain entities, and in others it reuses the model defined by the persistence layer. We revisit this issue in chapter 3.
■ Persistence layer—The persistence layer is a group of classes and components responsible for storing data to, and retrieving it from, one or more data stores. This layer necessarily includes a model of the business domain entities (even if it’s only a metadata model).
■ Database—The database exists outside the Java application itself. It’s the actual, persistent representation of the system state. If an SQL database is used, the database includes the relational schema and possibly stored procedures.
■ Helper and utility classes—Every application has a set of infrastructural helper or utility classes that are used in every layer of the application (such as Exception classes for error handling). These infrastructural elements don’t form a layer, because they don’t obey the rules for interlayer dependency in a layered architecture.
(这个就是那个界定layer的rules了)
Let’s now take a brief look at the various ways the persistence layer can be implemented by Java applications. Don’t worry—we’ll get to ORM and Hibernate soon.There is much to be learned by looking at other approaches.
1.3.2 Hand-coding a persistence layer with SQL/JDBC
The most common approach to Java persistence is for application programmers to work directly with SQL and JDBC. After all, developers are familiar with relational database management systems, they understand SQL, and they know how to work with tables and foreign keys. Moreover, they can always use the well-known and widely used data access object (DAO) pattern to hide complex JDBC code and nonportable SQL from the business logic.
The DAO pattern is a good one—so good that we often recommend its use even with ORM
(就是应用了ORM后,DAO也很是有用). However, the work involved in manually coding persistence for each domain class is considerable, particularly when multiple SQL dialects are supported. This work usually ends up consuming a large portion of the development effort. Furthermore, when requirements change, a hand-coded solution always requires more attention and maintenance effort.
Why not implement a simple mapping framework to fit the specific requirements of your project? The result of such an effort could even be reused
(这个reused就成了Hibernate的萌芽!)in future projects. Many developers have taken this approach; numerous homegrown object/relational persistence layers are in production systems today. However, we don’t recommend this approach. Excellent solutions already exist: not only the (mostly expensive) tools sold by commercial vendors, but also open source projects with free licenses. We’re certain you’ll be able to find a solution that meets your requirements, both business and technical. It’s likely that such a solution will do a great deal more, and do it better, than a solution you could build in a limited time.
Developing a reasonably full-featured ORM may take many developers months. For example, Hibernate is about 80,000 lines of code, some of which is much more difficult than typical application code, along with 25,000 lines of unit test code. This may be more code than is in your application. A great many details can easily be overlooked in such a large project—as both the authors know from experience! Even if an existing tool doesn’t fully implement two or three of your more exotic requirements, it’s still probably not worth creating your own tool. Any ORM software will handle the tedious common cases—the ones that kill productivity. It’s OK if you need to hand-code certain special cases; few applications are composed primarily of special cases.
1.3.3 Using serialization
Java has a built-in persistence mechanism: Serialization provides the ability to write a snapshot of a network of objects (the state of the application) to a byte stream, which may then be persisted to a file or database
(把这样的byte stream再放进DB中又会有什么益处?为什么不直接把相应数据放进DB呢?). Serialization is also used by Java’s Remote Method Invocation (RMI) to achieve pass-by value semantics for complex objects
(这个也一直没接触过,有机会试试). Another use of serialization is to replicate application state across nodes in a cluster of machines.
Why not use serialization for the persistence layer? Unfortunately, a serialized network of interconnected objects can only be accessed as a whole; it’s impossible to retrieve any data from the stream without deserializing the entire stream. Thus, the resulting byte stream must be considered unsuitable for arbitrary search or aggregation of large datasets. It isn’t even possible to access or update a single object or subset of objects independently. Loading and overwriting an entire object network in each transaction is no option for systems designed to support high concurrency.
Given current technology, serialization is inadequate as a persistence mechanism for high concurrency web and enterprise applications. It has a particular niche as a suitable persistence mechanism for desktop applications.
1.3.4 Object-oriented database systems
Because we work with objects in Java, it would be ideal if there were a way to store those objects in a database without having to bend and twist the object model at all. In the mid-1990s, object-oriented database systems gained attention. They’re based on a network data model, which was common before the advent of the relational data model decades ago. The basic idea is to store a network of objects, with all its pointers and nodes, and to re-create the same in-memory graph later on.This can be optimized with various metadata and configuration settings.
An object-oriented database management system (OODBMS) is more like an extension to the application environment than an external data store. An OODBMS usually features a multitiered implementation, with the backend data store, object cache, and client application coupled tightly together and interacting via a proprietary network protocol. Object nodes are kept on pages of memory, which are transported from and to the data store.
Object-oriented database development begins with the top-down definition of host language bindings that add persistence capabilities to the programming language. Hence, object databases offer seamless integration into the object-oriented application environment. This is different from the model used by today’s relational databases, where interaction with the database occurs via an intermediate language (SQL) and data independence from a particular application is the major concern.
For background information on object-oriented databases, we recommend the respective chapter in An Introduction to Database Systems (Date, 2003).
We won’t bother looking too closely into why object-oriented database technol ogy hasn’t been more popular; we’ll observe that object databases haven’t been
widely adopted and that it doesn’t appear likely that they will be in the near future. We’re confident that the overwhelming majority of developers will have far more opportunity to work with relational technology, given the current politi cal realities (predefined deployment environments) and the common require ment for data independence.
1.3.5 Other options
Of course, there are other kinds of persistence layers. XML persistence is a varia tion on the serialization theme; this approach addresses some of the limitations of byte-stream serialization by allowing easy access to the data through a stan dardized tool interface. However, managing data in XML would expose you to an object/hierarchical mismatch. Furthermore, there is no additional benefit from the XML itself, because it’s just another text file format and has no inherent capabilities for data management. You can use stored procedures (even writing them in Java, sometimes) and move the problem into the database tier. So-called object-relational databases have been marketed as a solution, but they offer only a more sophisticated datatype system providing only half the solution to our problems (and further muddling terminology). We’re sure there are plenty of other examples, but none of them are likely to become popular in the immedi ate future.
Political and economic constraints (long-term investments in SQL databases), data independence, and the requirement for access to valuable legacy data call for a different approach. ORM may be the most practical solution to our problems.