20.2. Principles of HibernateOften, programmers tend to skip introductory material and move right to the code. Sometimes we skip the code examples too and just pull up a seat at the keyboard and start hacking. Tempting as it may be to do so, plowing ahead without understanding the principles that Hibernate was built on is a dangerous thing to do. While persistence frameworks are meant to make life easier, they can be your worst nightmare if you don't understand the principles that drive the framework. 20.2.1. TransparencyFirst and foremost, Hibernate strives to be a transparent service provider. When authoring an application, your customer derives value not from the choice of tools you use to create an implementation but from the domain model you create to solve his real-world problems. That domain model should be as testable, portable, and deployable as possible. Hibernate goes to great lengths to ensure that your application is as minimally dependent on it, its libraries, and its own dependencies as possible. This means that the domain objects themselves are oblivious to the persistence mechanism you employ. They implement no interfaces, extend no base classes, refer to no APIs, nor even make any design concession to the Hibernate framework. The persistence logic and APIs are encapsulated away in the façade layer, allowing your domain objects to be truly domain-specific. 20.2.2. ReflectionAny ORM framework must provide a way to dynamically generate SQL CRUD (create, read, update, delete) statements to bridge the chasm between the running application and the persistence store. When things change in the domain, the framework has to know about them to persist them to the data store and vice versa. This means that the ORM framework has to have knowledge of the specifics of not only the class definitions but also the runtime instances of those classes. That kind of dynamic knowledge can come from one (or more) of three sources:
When most Java programmers are asked for their first thoughts about the Reflection API, the word that pops from their mouths is "slow." While it's true that calls made through reflection are necessarily slower than native calls with direct manipulation of Java classes, the difference between the two has been closing with each release of the JVM. The Hibernate team explicitly chose reflection because it has minimal impact on the build process for an application and because the impact of having a few reflective calls will be hidden by any actual access to the database, which is where most applications incur most of their operational cost. The other two choices, bytecode injection and code generation, change the build process of an application and result in code being inserted into your domain classes. While not inherently bad, the Hibernate team chose instead to keep your domain classes unencumbered with extraneous service code by choosing reflection. 20.2.3. Java, JDBC, and RDBMSHibernate is a framework that specifically provides for transparent persistence of Java objects over JDBC[1] to a relational database management system. This specificity allows Hibernate to provide performance optimizations and general ease-of-use features that would otherwise be more difficult.
20.2.4. PluggabilityHibernate provides a variety of services to an application: transaction management, caching, optimizations, and so on. These services might be adequate for a broad spectrum of applications, but sometimes application requirements call for specific service providers or features from the service that the Hibernate version cannot support. Hibernate allows for almost every service in its libraries to be replaced by a third-party implementation, usually through nothing more than a change to the configuration files. 20.2.5. PerformanceHibernate is designed to provide high-performance access to a relational database. In the most basic sense, the Hibernate API is designed to favor patterns and programming decisions that allow for high concurrency by not holding open JDBC connections for longer than absolutely necessary. Additionally, Hibernate caches SQL statements to be executed as late as possible in large batches and holds prepared statements for faster execution. Through optimization techniques like lazy loading and proxy initialization, Hibernate gives developers still more control over the performance of their applications. Last, through a series of debugging and monitoring features, developers can learn detailed information about how well their application performs both at development and deployment time. |