Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Notes on Hibernate Created 03/22/04 Updated 10/24/04, Updated 07/23/05, Updated 10/21/05, Updated 03/28/06, Updated 06/08/06, Updated 11/12/06 Updated 12/22/06, Updated 02/10/07, Updated 03/02/07, Updated 04/02/07, Updated 06/07/07, Updated 07/22/07 Updated 08/05/07, Updated 11/15/07, Updated 01/27/08, Updated 03/20/08, Updated 05/20/08, Updated 06/08/08 Updated 07/20/08, Updated 09/08/08, Updated 12/12/08, Updated 12/21/08, Updated 01/25/09, Updated 03/13/09 Updated 09/14/09, Updated 10/13/09, Updated 08/22/10, Updated 10/02/10, Updated 01/21/11, Updated 02/27/11 Updated 08/31/12, Updated 09/21/13, Updated 12/22/14, Updated 05/03/15, Updated 11/04/15 Overview Hibernate is an Object/Relational Mapping tool, which supports a range of databases. From the www.hibernate.org web site: Hibernate is a powerful, ultra-high performance object/relational persistence and query service for Java. Hibernate lets you develop persistent classes following common Java idiom - including association, inheritance, polymorphism, composition, and the Java collections framework. Hibernate allows you to express queries in its own portable SQL extension (HQL), as well as in native SQL, or with Java-based Criteria and Example objects. Another goal of Hibernate is to remove the presence of SQL from the Java application (or at least from the nondatabase portions). Typical applications based on Hibernate use a design which is partitioned into presentation objects, business objects, and data access objects in an MVC relationship. Finally, a goal of these tools is to remove impact of different “dialects” of database implementation, such as the difference between Oracle and MySQL for example. When you consider that these are both leading implementations of SQL, but have slightly different datatypes, query syntax, sequence generators, and connection strings, it is easy to see why this is important. In all mapping-based tools, maintaining the matches between the database, the Java classes, and the mapping files can be a significant effort, and there are different approaches, which can be organized around the chronology of “which piece of the implementation is the master embodiment of the design”. For instance: Top down: you start with an existing domain model, and its implementation in Java. Quite common. Bottom up: you start with an existing database schema and data model. Quite common. Middle out: you start by generating the mapping files, since the mapping metadata provides sufficient information to completely deduce the database schema and to generate the Java source code for the persistence layer. Recommended only for designers who have great familiarity with the mapping file concept and representation. Meet in the middle: you have an existing set of Java classes and an existing database schema for which there may or may not be simply mapping. Some refactoring will probably be needed, and so this is the most complex of the four cases. There are tools within Hibernate to carry out the “top down” approach (called hbm2ddl), and the “bottom up” approach (called hbm2java). In addition there are database reverse engineering tools in MyEclipse and others. Both of these Hibernate tools could be used to carry out the “middle out” approach, after the mapping files are created. For the last approach, you are largely on your own. There are several layers to Hibernate and its distributions: Hibernate Core: this is the primary API to Hibernate and its mapping files. All of the discussion in this document is about Hibernate Core, except for those sections covering use of Hibernate Annotations. Hibernate Annotations: this is alternate way of specifying mapping information, by using Annotations in your Java files, similar to how XDoclet operates. By keeping the mapping data locally, the number of files to keep in sync is reduced. Since late 2007, we have been using Hibernate Annotations almost exclusively. Hibernate Validator: this is a different approach to validation from the usual approach used in JSF: rather than having the validation rules expressed on the editing views, the validation rules are expressed on the entity definitions (in both cases, they are carried out on the server side). Page 1 of 32 Hibernate EntityManager: this is a set of tools that implement EJB 3.0 entity persistence, which is based on Hibernate. During 2007 this was not highly important, as we were using Hibernate directly, but in 2008 with JBoss, understanding the EntityManager became important. Hibernate Tools: this is described as an entirely new toolset for Hibernate3, implemented as an integrated suite of Eclipse plugins, together with a unified Ant task for integration into the build cycle. Hibernate Tools is a core component of JBoss Eclipse IDE. Hibernate Core comes with C3P0, which is a pooling system like DBCP. However, C3P0 won't block in synchronized code like DBCP can. One note: recommend setting numHelperThreads up above 6 to limit the pool size under load. Hibernate appears to have more industry support than any other O/R mapping tool. Hibernate is a professional Open Source project and a critical component of the JBoss Enterprise Middleware System (JEMS) suite of products. For instance, there are far more books and resources available, it is referred to more often in the hiring requirements of companies surveyed on CraigsList (during our research of 2006-2007), and it has become the persistence model of the EJB 3.0 specification and implementations (called JPA, for Java Persistence API). Layers This shows the most of Hibernate is located in the Session class, which holds the state information, and used in most of the API calls. Sessions come from a SessionFactory, which is based on a Configuration facility. Above the session are classes for generating queries, such as the Query and Criteria classes, and code for managing the transactions. For some reason this diagram implies that application code is using the Session rather than the Query facilities, while in fact the most common classes in DAO’s of the application are Query and Criteria classes. But perhaps this represents the fact that to persist an object, you call a method on the Session object. Not shown below this diagram are the database connection management, pooling, and caching facilities. Released Versions In Dec 2012, Hibernate ORM 4.1.9 Final was released.[4] In Dec 2011, Hibernate Core 4.0.0 Final was released. This includes new features such as multi-tenancy support, introduction of ServiceRegistry (a major change in how Hibernate builds and manages "services"), better Session opening from SessionFactory, improved integration via org.hibernate.integrator.spi.Integrator and auto discovery, internationalization support and message codes in logging, and a clearer split between API, SPI and implementation classes.[3] The first 3.6.x releases came out in late 2010. Grails 2.2.4 is still using 3.6.10 as of Summer 2013. The prior series is 3.5.6, released September 15, 2010. Hibernate 3.5.x came out in April 2010, and includes Page 2 of 32 JSR 317 (JPA2) support. Integration of hibernate-annotations, hibernate-entitymanager and hibernate-envers into the core project. See http://in.relation.to/14172.lace for details Added Infinispan as a standard second-level cache. See http://infinispan.blogspot.com/2009/10/infinispanbased-hibernate-cache.html for details Improvements to the new second-level caching SPI introduced in 3.3 based on feedback from implementers including Ehcache, Inifinispan and JBoss Cache. Far better read only / immutable support. See the new chapter added to the core reference manual dedicated to the subject. Support for JDBC 4 such that Hibernate can be used in JDK 1.6 JVMs and make use of JDBC4-compliant drivers.' Support for column-level read/write fragments (HBM only for now) Initial support for fetch profiles. Hibernate 3.4.x came out in 2009, and addresses the following goals: A fix for an out of memory error generated upon calling list() in getSingleResult. A fix to an exception in the EntityManager during the deletion of an entity. The ability to build independent of the Hibernate Core Structure. An upgrade to Hibernate Core 3.3. Hibernate 3.3.x came out in November 2008, and addresses the following goals: Redesigned, modular JARs - There are now a number of fine-grained JARs rather than one large JAR - this allows users to more easily see and minimize their dependencies, and allows organizations to build customized Hibernate deployments with unwanted parts left out Maven-based build - Hibernate is now built using the Apache Maven build system Revamped caching SPI - Based on feedback, the cache system has been refactored to allow more finegrained control of the characteristics of different cache regions JBoss Cache 2.x integration - Based upon the new caching SPI, JBoss Cache 2.x integration is now available out-of-the-box There are some Hibernate 3.3 upgrade notes at http://www.agileapproach.com/blog-entry/hibernate-33-upgrade-tips Hibernate 3.2 came out in late 2006, and adds Java Persistence compliance (the Java Persistence API is the standard object/relational mapping and persistence management interface of the Java EE 5.0 platform). It appears that the 3.2 release was a major milestone and is a reference version, as the primary authors of Hibernate have updated their main book to match this version. The version used in JBoss 4.2.3 is Hibernate 3.2.4sp1. The final version of the 3.2 release series was 3.2.7. Hibernate 3.0 came out in late 2004, and reached 3.0.5 as a bug fix release by early 2005. Note that the number of libraries used by Hibernate increased greatly during this time. Hibernate 3.0 increases the mapping capabilities, adds support for association joins based on SQL formulas and for SQL formulas defined at the <column> level. There were versions of Hibernate 2.x during 2004 and very early 2005. They are important now only in that they are the documented version in several Hibernate books written during 2004 to 2005. At Menlo School, we were running release 3.0.5 during late Spring 2006, and switched to 3.2 in November 2006, and to 3.2.2 in February 2007. We switched to 3.2.4sp1 for JBoss 4.2.3-based projects in late 2008, and began to evaluate 3.3.1 and 3.3.2 for native projects (mostly test programs). Resources for Information on Hibernate The Hibernate web site supplies the reference documentation, and a set of FAQ’s. These questions link to some simple tutorials. The reference documentation PDF was 212 pages long as of Hibernate 2.1, and is 342 pages as of 3.3.2. There is a one-page quickref to the Hibernate API that is handy for review. However, it is the books that carry the main discussion about the concepts and patterns of use, and only the books have enough examples to communicate some of the more complex concepts and patterns. Page 3 of 32 “Java Persistence with Hibernate” by Christian Bauer and Gavin King. Manning Press, November 2006, 904 pages. List price $49.99, Amazon price $32.99, used from $28.44. Rated 3.5 stars on Amazon.com. This should be thought of as the second edition of “Hibernate in Action” (by the same authors) and this book is the one to buy. We got a copy in late December 2006. It is twice as long as the prior edition, and covers the tools and process for converting schema definitions to Java classes and vice versa. Expanding considerably on the reference material provided in the download, this book is invaluable. What is somewhat confusing about the book is that for each topic, it has sections that describe how to do it with Hibernate Core, then with Hibernate Annotations instead of the XML files, then with the JPA annotations and calls (this haphazard organization is what has caused the book to get some less-positive reviews). “Harnessing Hibernate” by James Elliot, Tim O’Brian, and Ryan Fowler. O’Reilly Press, April 2008, 380 pages. List price $39.99, Amazon price $26.20, used from $22.60. Rating 4 stars on Amazon.com. This appears to be O’Reilly’s answer to Manning’s coverage of Hibernate, and is considered to be well-written. However, from reviewing it in the bookstore, it doesn’t appear to cover anything regarding Hibernate that isn’t in the above book, but it does add material about Spring, Stripes, and Maven. “Hibernate: A J2EE Developer’s Guide” by Will Iverson. Addison-Wesley, November 2004, 351 pages. List price $39.99. Amazon price $26.01, used for $3.75. Discusses Hibernate 2.1.2, and is largely parallel to the Bauer/King book first edition (which was written at the same time). It has chapters on setting up Hibernate, starting schema from Java classes, starting schemas from an existing database, mapping, transactions, etc. The Bauer/King book is generally getting better reviews. “Pro Hibernate 3 (Expert’s Voice Series)” by Jeff Linwood, Dave Minter. APress, July 2005, 242 pages. List price $39.99. Amazon price $26.39, used for $19.99. Comments on this book were mixed, and I have only glanced at it in the bookstore. Its main strength is that it was the first book to cover Hibernate 3’s API, but I don’t think that it adds much beyond the reference manual materials. “Hibernate: A Developer’s Notebook” by James Elliot. O’Reilly Press, May 2004, 170 pages. List price $24.95. Amazon price $16.47, used price $12.00. Rather dated now. This is part of the “lab notebook” approach to learning new pieces of software, in which you are given very specific steps of installing and running Hibernate. Goes into great detail about the Ant scripts that you would write to run the tools, set up the database, etc. Uses HSQLDB and MySQL for the examples. We got a great deal out of it, but found that we next needed to know much more about the mapping files and the API that this book provided. There is an article from OnJava in April 2005, http://www.onjava.com/pub/a/onjava/2005/08/03/hibernate.html that discusses various uses of formula mappings in Hibernate3. There are also tools for using Hibernate provided within MyEclipse. They are documented in our document “Notes on MyEclipse”. There are also tools for using Hibernate provided in the JBoss Tools download. They are documented in our document “Notes on JBoss Tools”. Minimum Set of Libraries Using guidance from the MyEclipse and Hibernate 3.3.1 materials, plus taking in the most up-to-date of the required Apache libraries, we have concluded that the following set is the minimum set of libraries for using Hibernate at runtime in our applications: Page 4 of 32 (The junit-4.4.jar is not actually needed, except for tests with our application). This set of libraries supports all of the standard session management, content mapping, query management, and insert/update/delete behavior, plus annotations and transactions. While Hibernate appears to have far more libraries shipped wit hit, they appear to be needed only for doing schema generation, jBoss linkage, JMX linkage, reverse engineering, etc. These version numbers are current as of February 2007. Note that Hibernate is now using slf4J instead of log4j. There is also a requirement to have a log4.properties in order to avoid getting a warning about lack of appenders for Hibernate to use. The shortest contents are: # A log4j configuration file. # The root logger uses the appenders called A1 and A2. Since no # priority is set, the root logger assumes the default which is one of # TRACE, DEBUG, INFO, WARN, ERROR, FATAL log4j.rootLogger=INFO, STDOUT # STDOUT is set to be ConsoleAppender sending its output to System.out log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender # STDOUT uses PatternLayout. log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout # The conversion pattern log4j.appender.STDOUT.layout.ConversionPattern=%-5d %-5p [%t] %c{2} - %m%n Hibernate Annotations The Hibernate Annotations facility is a huge step forward in reducing the number of configuration files that are used. The Hibernate Annotations package includes: Standardized Java Persistence and EJB 3.0 (JSR 220) object/relational mapping annotations Hibernate-specific extension annotations Annotations for data integrity validation with the included Hibernate Validator API Domain object indexing/searching for Lucene via the included Hibernate Lucene framework Requirements: At a minimum, you need JDK 5.0 and Hibernate Core, but no application server or EJB 3.0 container. You can use Hibernate Core and Hibernate Annotations in any Java EE 5.0 or Java SE 5.0 environment. Page 5 of 32 The current release is 3.4.0 GA, released on 08/20/2008. It consists of two libraries: hibernate-annotations.jar and hibernate-commons-annotations.jar, and it requires the library ejb3-persistance.jar. Here is an example of using the annotations facility: @Entity @Table(name="language") public class Language { private String isoCode; private String description; @Id @Column(name="code", length=5) public String getIsoCode() { return this.isoCode; } public void setIsoCode(String isoCode) { this.isoCode = isoCode; } public String getDescription() { return this.description; } public void setDescription(String description) { this.description = description; } } The important annotations are @Entity, @Table, and @Column. These are sufficient for describing simple classes. More complex tags are introduced in the material below as the more complex mapping examples are discussed. Since these annotations are also the specifications of the SQL schema that will be generated, it is important to add the annotations that define the SQL (even if they have minimal effect on the Java), such as: length for strings: Put this in the @Column annotation. Default 255. nullable: to indicate what fields can be null. Put this in the @Column annotation. Default false precision, scale for numbers. Put this in the @Column annotation. Default 0 and 0 unique: Put this in the @Column annotation. default false datetimes, annotated with @Temporal Hibernate and HSQL Many of the Hibernate examples focus on using the in-memory database called HSQL. This was formerly called “Hypersonic SQL”, and is unrelated to Hibernate itself. Since HSQL is distributed with JBoss, some of the reasons for using it include ease of set-up and administration. The best way to use it is to have Hibernate generate a schema, using annotations, and then specify the following in the Hibernate configuration: Basic Configuration for Hibernate The Configuration object holds all configuration data, and can be populated by reading an XML file (defaults to hibernate.cfg.xml. This file defines session configuration data, as well as related resource data, such as the pointers to the mapping files. The mapping files are typically located with the Java classes that they map, and there is typically only one class per mapping file. Here is an example: <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> Page 6 of 32 <session-factory> <property name="show_sql">true</property> <property name="connection.url"> jdbc:mysql://localhost:3306/in </property> <property name="connection.username">root</property> <property name="connection.password">root</property> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <mapping resource="dto/User.hbm.xml" /> <mapping resource="dto/Role.hbm.xml" /> <mapping resource="dto/Location.hbm.xml" /> </session-factory> </hibernate-configuration> You can enable automatic export of a schema when your SessionFactory is built by setting the hibernate.hbm2ddl.auto configuration property to create or create-drop. The first setting results in DROP statements followed by CREATE statements when the SessionFactory is built. The second setting adds additional DROP statements when the application is shut down and the SessionFactory is closed—effectively leaving a clean database after every run. Also note that since Hibernate 3.1 you can include a file called “import.sql” in the runtime classpath of Hibernate. At the time of schema export it will execute the SQL statements contained in that file after the schema has been exported. However, we have had real problems with this: the import.sql file cannot contain multi-line statements, which makes it very hard to read (since insert statements with many fields becomes a very long line of text). So we don’t use this approach much. Configuration Facilities and Basic API Calls The API includes classes and factory objects for sessions, transactions, queries, criteria, etc. In addition, the Session object has calls to save or persist an object. Configuration The Configuration object holds all configuration data, and can be populated by reading an XML file (defaults to hibernate.cfg.xml. This file defines session configuration data, as well as related resource data, such as the pointers to the mapping files. The mapping files are typically located with the Java classes that they map, and there is typically only one class per mapping file. Sessions Get the SessionFactory from the configuration object, and then open a session. At the end of using the session (typically after a sequence of query/update operations), close the session, and then close the SessionFactory. Given a SessionFactory, a session can be made for a specific Connection. The Connection class is part of java.sql. Transactions If a session is being used only for reading content, you need not have a transaction pending. However, if the session is being used to save or update objects, this must be done on a session with a transaction pending. Writes are held until the transaction is closed by committing it. The transaction is represented by a distinct object, which is created from the Session object. Page 7 of 32 Queries and Criteria These are description of SQL queries and their where clauses, expressed in terms of the objects that correspond to the tables. Example Code The following code, from a test framework, shows examples of each of the above object (other than Queries and Criteria): @Override protected void setUp() throws Exception { config = new AnnotationConfiguration(); config.configure(); sessionFactory = config.buildSessionFactory(); newSession = sessionFactory.openSession(); newTransaction = newSession.beginTransaction(); } @Override protected void tearDown() throws Exception { newTransaction.commit(); newSession.close(); sessionFactory.close(); } Programmatic Generation of Schema The SchemaExport class is the key to having Hibernate generate schema and install it in the database (to avoiding having to “mysql source” it yourself. Create a SchemaExport object as follows: Configuration cfg = new Configuration().configure(); SchemaExport schemaExport = new SchemaExport(cfg); Key attributes of SchemaExport are: String delimiter -- string to place at the end of each line Boolean format – true/false if the output should be broken up into several lines for readability (generally true, but the default is false) String outputFile – name of file to write with content. There is one key method on this class (most of the other methods are calls to this): public void execute(boolean script, boolean export, boolean justDrop, boolean justCreate) { log.info( "Running hbm2ddl schema export" ); … if ( export ) { log.info( "exporting generated schema to database" ); connectionHelper.prepare( true ); connection = connectionHelper.getConnection(); statement = connection.createStatement(); } if ( !justCreate ) { drop( script, export, outputFileWriter, statement ); } if ( !justDrop ) { create( script, export, outputFileWriter, statement ); Page 8 of 32 if ( export && importFileReader != null ) { importScript( importFileReader, statement ); } } log.info( "schema export complete" ); } From this, we can document the four boolean flags as follows: script – if true, the output will be written to System.out as well as the database and the outputFileName. export – if true, the database must be connected to and dropped/created using the flags below justDrop – if true, the creation of new schema is disabled justCreate – if true, the dropping of prior database schema is disabled Domain Models and Metadata Here is a sample data model, which is from the Caveat Emptor project. Writing Mapping Files Here is a simple example of a mapping file: <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.storm.model.LocationDTO" table="Location"> <id name="id" column="location_id" type="int"/> <property name="name"> <column name="NAME" length="16" not-null="true"/> Page 9 of 32 </property> <many-to-one name="type" column="LocationType_ID" class="com.storm.model.LocationTypeDTO" not-null="true"/> </class> </hibernate-mapping> There are three primary cases to be dealt with: Single: Those which are keys are done through the <id> tag. Those which are not keys are done through the <property> tag. Many-to-one: using the <many-to-one> element, and specifing the related class. One-to-many: this is discussed under “Using Associations”, below. Many-to-many: this is discussed under “Using Associations”, below. Here is a many-to-one mapping, where a product has a productType: <class name="com.storm.model.ProductDTO" table="product"> <id name="productId" type="java.lang.Integer"> <column name="Product_ID" /> <generator class="increment" /> </id> <property name="productName" type="java.lang.String"> <column name="ProductName" length="50" /> </property> <many-to-one name="productType" column="ProductType_ID" class="com.storm.model.ProductTypeDTO" not-null="true"/> </class> Here is a one-to-many mapping, where an album has a list of many pictures. <class name=”com.storm.model.AlbumDTO” table=”album”> <set name="tracks" lazy="false"> <key column="ALBUM_ID"/> <one-to-many class="com.storm.model.TrackDTO"/> </set> </class> Here is sample of a many-to-many mapping, where a user as a list of roles, and other users have the same roles: <set name="roles" table="usersrole" inverse="true"> <key column="USERS_ID"/> <many-to-many column="Role_ID" class="com.storm.model.RoleDTO"/> </set> There is also a facility for defining “formula columns”, these are ones for which the generated query contains a SQL expression with restrictions and is run by the database. <class name="Product" table="Product"/> <id name="productId" length="10"> <generator class="assigned"/> </id> <property name="description" not-null="true" Page 10 of 32 length="200"/> <property name="price" length="3"/> <property name="numberAvailable"/> <property name="numberOrdered"> <formula> ( select sum(li.quantity) from LineItem li where li.productId = productId ) </formula> </property> </class> The formula doesn’t have a column attribute, and never appears in SQL update or insert statements, only selects. Formulas may refer to columns of the database table, they can call SQL functions, and they may even include SQL subselects. The SQL expression is passed to the underlying database as is – so avoid database vendor specific syntax of functions or the mapping file will become vendor specific. Examples of Annotations @Entity @Table(name="language") public class Language { private String isoCode; private String description; @Id @Column(name="code", length=5) public String getIsoCode() { return this.isoCode; } public void setIsoCode(String isoCode) { this.isoCode = isoCode; } public String getDescription() { return this.description; } public void setDescription(String description) { this.description = description; } } The Table-level annotations specify the table name (which would define to the class name, anyway). The table level association can also have a uniqueness constraint, which specifies the columns to be combined in forming the unique constraint. For instance, you might have: @Table(name=”Role”, uniqueConstraints = @UniqueConstraint( columnNames = { “name” } )) This would provide a database-level check of unique names for the roles. Some of the most commonly-used relationships are many-to-one relationships. Suppose, in the above example, that each ModelPlane is associated with a PlaneType via a many-to-one relationship (in other words, each model plane is associated with exactly one plane type, although a given plane type can be associated with several model planes). You could map this as follows: @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} ) @JoinColumn(name=”planeType_id”, nullable=false) @ForeignKey(name=”FK_PlaneType_Plane”) public PlaneType getPlaneType() { return planeType; } Page 11 of 32 The CascadeType values indicate how Hibernate should handle cascading operations. In this case, the join column is being given a name (if not specified, the join column would simply be “planeType”). In this case, the index which is built for the relationship is being given a name (if not specified, the index name would be a cryptic string of hexadecimal digits, at least for the MySQL dialect). Another commonly-used relationship is the opposite of the above: the one-to-many-to-one relationship, also known as a collection. Collections are complex beasts, both in old-style Hibernate mapping and when using annotations, and we'll just be skimming the surface here to give you an idea of how it's done. For example, in the above example, each PlaneType object may contain a collection of ModelPlanes. You could map this as follows: @OneToMany(mappedBy="planeType", cascade=CascadeType.ALL, fetch=FetchType.EAGER) @OrderBy("name") public List<ModelPlane> getModelPlanes() { return modelPlanes; } Many to Many with Join Tables Suppose you are linking products to Items in a many-to-many way, and also wish to record price on a pair wise combination basis. Use the following approach, which is based on page 304 of the “Java Persistence with Hibernate” book: @Entity @Table(name="ordered_lines") public class OrderLine { @Embeddable public static class Id implements Serializable { @Column(name="order_id") private Long orderId; @Column(name="product_id") private Long productId; public Id() {} public Id(Long orderId, Long productId) { this.orderId = orderId; this.productId = productId; } public boolean equals(Object o) { // compare this and that Id properties (orderIds and productIds) } public int hashCode() { // add the orderId and productId hashCode()s } } @EmbeddedId private Id id = new Id(); @ManyToOne @JoinColumn( name="order_id", insertable="false", updatable="false" Page 12 of 32 ) private Order order; @ManyToOne @JoinColumn( name="product_id", insertable="false", updatable="false" ) private Product product; // create attributes you want to save in the join table public OrderedLine() {} public OrderedLine( Order order, Product product /* other attributes */) { this.id.orderId = order.getId(); this.id.productId = product.getId(); // these are two one-to-many relationships mapped // one in each of Order and Product order.getOrderLines().add(this); order.getOrderLines().add(this); // set other attributes } // accessor methods } For reasons that we don’t know, it is required that the annotations be placed on the field declarations, rather than on the get methods. Id Generation There are several different approaches, which were listed above. In our examples, we have been using the “increment” mode; however, this will have a problem if there are multiple applications hitting the same database. Sequences or identity columns are really the way to go, since they are consistent across all users of the database. On MySQL tables which have “auto-increment” in the id columns, you could use the “identity” approach, which would also be used by the “native” approach. It is also possible to write your own id generator, using a Hibernate API. There was a very important reference document on Id generation in Hibernate. It is located at “Don’t Let Hibernate Steal Your Identity”, and makes the following points: Unless you define hashCode() and equals() in a meaningful way, Hibernate will be unable to determine if to objects represent the same database row. Defining hashCode() and equals() to use the id fields of the object can be problematic, since objects which have not yet been persisted will all be treated as the same. Implementing hashCode() and equals() to have values that change when the fields are modified breaks a requirement of Java Collections API. The article concludes by suggesting that you don’t have Hibernate manage your ids, or use the generator in the database, but instead have code in your application which creates GUID’s whenever a persistable object is created. Page 13 of 32 For describing an identity column through annotations, use the following: @Id @Column(name = "users_id") @GenericGenerator(name = "generator", strategy = "increment") @GeneratedValue(generator = "generator") Mapping Information used by Hibernate Tools Most of our early examples have attribute such as “length” and “not-null” in the mapping files. It turns out that these are used only the Hibernate tools such as the ones that generate database schema or Java classes source code. While most of the discussion here is about the Core Hibernate in which name, type, key, column, and table information is needed, one of the goals of the mapping file specification is that it includes ALL information needed to generate the schema or Java class source code. This matches the “middle-out” development approach. Examples of other information can be included is: <id name=”id” type=”int” column=”TRACK_ID”> <meta attribute=”scope-set”>protected</meta> <generator class=”native”/> </id> <property name=”added” type=”date”> <meta attribute=”field-description”>When the track was added</meta> </property> This will generate a protected set method for “id”, and will add some comments in the header for the get method for “added”. Mapping Associations Recall that in Hibernate jargon an entity is an object that stands on its own in the persistence mechanism: it can be created, queried, and deleted independently of any other objects, therefore has its own persistent identity. A component, in contrast, is an object that can be saved to and retrieved from database, but only as a subordinate part of some entity. These are defined using the set tag. For example: <set name=”bids” inverse=”true” cascade=”all-delete-orphan”> <key column=”item_Id” /> <one-to-many class=”Bid” /> </set> The outer-join attribute is deprecated. Use fetch="join" and fetch="select" instead of outer-join="true" and outerjoin="false". Existing applications may continue to use the outer-join attribute, or may use a text search/replace to migrate to use of the fetch attribute. To control cascaded deletes, use cascade=”add-delete-orphan” on the association mapping. This means part of the <set> tag. When a many-to-many association is used it is important to set the cascade options to “save-update”. This shown in the following example: <class name="com.incra.modules.user.model.User" table="users" lazy="false"> Page 14 of 32 <id name="userId" type="java.lang.Integer"> <column name="USERS_ID" /> <generator class="increment" /> </id> <many-to-one name="organization" column="organizations_Id" class="com.incra.modules.user.model.OrganizationDTO" lazy="false" /> <set name="roles" table="usersrole" cascade="save-update" lazy="false" > <key column="USERS_ID" /> <many-to-many column="Role_ID" class="com.incra.modules.user.model.Role" /> </set> <property name="userName" type="java.lang.String"> <column name="NAME" /> </property> </class> In this case, a user has a many to one relationship to an organization, and a many to many relationship to roles. Over on the roles side, there is no reference to users for a role. This also implies that the “inverse” attribute is false (the default value) in the mapping shown above. If these settings are not established, then related data (such as the USERSROLE table) will not be updated correctly. The basic association mappings that correspond are @OneToOne, @ManyToOne, @OneToMany, @JoinTable, combined with a number of Hibernate-specific annotations such as “org.hibernate.annotations.CollectionOfElements”. A collection can also be sorted via a speciation in the Hibernate annotations. Composite Keys Here is an example in the mapping file: <hibernate-mapping> <class name="com.incra.modules.personalization.model.PresentationDTO" table="presentation" catalog="in" lazy="false"> <composite-id> <key-property name="userId" column="users_id" /> <key-property name="componentPath" column="componentPath" /> <key-property name="presentationName" column="PRESENTATIONNAME" /> </composite-id> <property name="fieldNames" type="java.lang.String"> <column name="fieldNameList" /> </property> </class> </hibernate-mapping> In this case, the object has a three-part key, which is composed of an integer and two strings. We have used this approach quite successful. We think that the compare method of the objects in question should be written to compare exactly these attributes, but we have not done that as yet. The discussion about composite keys is on page 303 of the “Java Persistence with Hibernate” book. Custom Types Hibernate allows you to define a new data type to be used in the mapping model, and register converter methods for that data type with the Hibernate SessionFactory. These converters work between the in-memory representation of the custom type, and persisted field or fields, which may be strings, integers, etc. Page 15 of 32 Most of the relevant discussion is located in Chapter 5 of the book. Polymorphic Mapping This topic deals with the issue of having a class hierarchy of for your java objects, but having no equivalent facility in the relational database. There are several approaches, which are covered in detail in Chapter 5 of the book: Table per concrete class with implicit polymorphism Table per concrete class with unions Table per class hierarchy Table per subclass In the first option “table per concrete class with implicit polymorphism” there is no knowledge of the class structure provided to the database or even the mappings. You simply write distinct mapping files for each class. This is a common starting point. In the second option “table per concrete class with unions”, there is a Hibernate mapping that includes the superclass, such as: <class name=”BillingDetails” abstract=”true”> <id name=”id” /> <property name=”name” column=”OWNER” /> <union-subclass name=”CreditCard” table=”CREDIT_CARD” > <property name=”number” /> <property name=”expMonth” /> </union-subclass> <union-subclass name=”BankAccount” table=”BANK_ACCOUNT” > <property name=”acctId” /> <property name=”branchLoc” /> </union-subclass> </class> In the third option, “table per class hierarchy”, all of the classes of the hierarchy are collapsed into one table, with a discriminator column. Here is an example: <class name="Work" table="works" discriminator-value="W"> <id name="id" column="id"> <generator class="native"/> </id> <discriminator column="type" type="character"/> <property name="title"/> <set name="authors" table="author_work"> <key column name="work_id"/> <many-to-many class="Author" column name="author_id"/> </set> <subclass name="Book" discriminator-value="B"> <property name="text"/> </subclass> <subclass name="Song" discriminator-value="S"> <property name="tempo"/> <property name="genre"/> </subclass> </class> Page 16 of 32 The final option, “table per subclass” is to represent inheritance relationships as relational foreign key associations. Every class/subclass that declares persistent properties - including abstract classes and even interfaces – has its own table. Unlike the table per concrete class strategy that we describe first, the table here contains columns only for the noninherited properties, and the tables are joined at fetch time to match the class is-a relationships. This approach can create more tables and more complex joins, and should be used cautiously. Persistent Enumerated Types If you use JDK 5.0, you can use the built-in support for type-safe enumerations. For example, a Rating class might look like: package auction.model; public enum Rating {EXCELLENT, OK, BAD} The Comment class has a property of this type: public class Comment { … public Rating rating; public Item auction; … } This is how you use the enumeration in the application code: Comment goodComment = new Comment(Rating.EXCELLENT, thisAuction); You can have Hibernate handle the mapping of the possible values into strings or integers in the database. In earlier versions of Hibernate you had to write a type handler for this, but in 3.2.x, you can just use the annotation @Enumerated. For more information, see our document “Notes on Java Enum Construct”. Working with Objects This material is derived from Chapter 9 of the book, which deals with the Persistence lifecycle. In many respects, the mapping file describes the static aspects of the Object/Relational mismatch, here we are dealing with the behavioral aspects, such as “when does an object get created? Or saved? Or restored? etc.” Chapter 9 is the first part of material called “Conversational Object Processing”. The conversation is between the application and the database, over time. Different ORM solutions use different terminology and define the different states and state transitions for the persistence lifecycle. The diagram is shown below: Page 17 of 32 The diagram can be summarized as follows: Objects created with the new operator are not immediately persisted. Their state is transient. A persistent instance is an entity instance with a database identity, such as having the id’s filled in. An object is in the removed state if it has been scheduled for deletion at the end of a unit of work, but it’s still managed by the persistence context until the unit of work completes. A detached object is one that was read from a persistence session, but the session has now been closed. Operations on Objects Loading of objects is done through the query or criteria objects, as described above. The most important concept to understand is that of lazy fetching. Associations are lazy by default. If you try to fetch a contained object that was lazy loaded, and the session is already closed (in other words, the object is “detached”), you will get a LazyInitializationException. Since it is best practice to map almost all classes and collections using lazy="true", that is the default. Here are the two most common operations on an object: session.save(object); session.delete(object); The session.save() operation works for either new objects or persisted objects that are being updated. As indicated above, these calls only work inside a transaction. We learned this the hard way. Page 18 of 32 There are a variety of options that can be specified in the mapping file to determine how Hibernate should generate the keys of new objects being persisted, or how Hibernate should handle the updating or deleting of objects associated with the object passed to save() or delete(). These are called “cascade” options, and are discussed below. In the JPA api, this is written as EntityManager.persist(myEntity). One of the most common errors incurred when using the save() function is “detached entity passed to persist”. There is a good explanation of this at https://forum.hibernate.org/viewtopic.php?p=2404032. The authors point out that the error message is unclear, it might better expressed as "cannot persist entity with identifier set manually AND via IdentifierGenerator”. For instance we got this error when the object being saved accidentally had a value in its id field. Further Discussion of Fetch Modes One of the most useful facilities in Hibernate is that although the fetch mode is specified in the annotations or the mapping file, it can be overridden for a specific query. Use the setFetchMode method on the Criteria object. This takes the following parameters: associationPath - a dot-separated property path mode - the fetch mode for the referenced association Typically, you set up the fetch modes to be Lazy in the annotations and mapping files, and then turn on FetchMode=JOIN only when needed. The meanings of the FetchModes are: static static static static static FetchMode DEFAULT FetchMode EAGER FetchMode JOIN FetchMode LAZY FetchMode SELECT Default to the setting configured in the mapping file. Deprecated. use FetchMode.JOIN Fetch using an outer join. Deprecated. use FetchMode.SELECT Fetch eagerly, using a separate select. In the Incra code framework, there was a method that accepted a list of field paths and would examine each one (going to the next-to-last field in the dotted set) to see what associationPaths needed to have the fetchMode.JOIN turned on. Then it would generate a criteria object, set the paths, and return the object. Generating Keys There are a variety of approaches which are available for generating keys or ids, with different overhead and different behavior. The most commonly used are: native: the native generator picks other generators, such as identity, sequence, or hilo, depending upon the capabilities of the database. Use this for portability. identity: supports the identity columns in MySQL, DB2, MS SQL Server, and Sybase. sequence: creates a sequence in DB2, PostgreSQL, Oracle, and SAP DB, and uses sequential values from it. increment: at startup, reads the maximum current value, then generates following values. Most database schema design literature goes through a discussion of why keys should not be related to a business domain function (such as social security numbers), because even though they appear to be unique, what happens if they are changed or replaced? Transaction Management In this chapter, we finally talk about transactions and how you create and control units of work in a application. We'll show you how transactions work at the lowest level (the database) and how you work with transactions in an application that is based on native Hibernate, on Java Persistence, and with or without Enterprise JavaBeans. Page 19 of 32 Transactions allow you to set the boundaries of a unit of work: an atomic group of operations. They also help you isolate one unit of work from another unit of work in a multiuser application. We talk about concurrency and how you can control concurrent data access in your application with pessimistic and optimistic strategies Transactions group many operations into a single unit of work. If any operation in the batch fails, all of the previous operations are rolled back, and the unit of work stops. Hibernate can run in many different environments supporting various notions of transactions. Standalone applications and some application servers only support simple JDBC transactions, whereas others support the Java Transaction API (JTA). Nonmanaged Environment Hibernate needs a way to abstract the various transaction strategies from the environment. Hibernate has its own Transaction class that is accessible from the Session interface, demonstrated here: Session session = factory.openSession(); Transaction tx = session.beginTransaction(); Event event = new Event(); //...populate the Event instance session.saveOrUpdate(event); tx.commit(); In this example, factory is an initialized SessionFactory instance. This code creates an instance of the org.hibernate.Transaction class and then commits the Transaction instance. In a nonmanaged environment, the JDBC API is used to mark transaction boundaries. You begin a transaction by calling setAutoCommit(false) on a JDBC Connection and end it by calling commit(). You may, at any time, force an immediate rollback by calling rollback(). Notice that you don't need to call session.flush(). Committing a transaction automatically flushes the Session object. The Event instance is persisted to the database when the transaction is committed. The transaction strategy you use (JDBC or JTA) doesn't matter to the application code-it's set in the Hibernate configuration file. Managed Environment In a managed environment, the JTA transaction manager is in control of the transactions. The following are benefits of managed resources with JTA and the reasons to use this J2EE service (it is available with both JBoss and Spring): A transaction-management service can unify all resources, no matter of what type, and expose transaction control to you with a single standardized API. This means that you can replace the Hibernate Transaction API and use JTA directly everywhere. It's then the responsibility of the application deployer to install the application on (or with) a JTA-compatible runtime environment. This strategy moves portability concerns where they belong; the application relies on standardized Java EE interfaces, and the runtime environment has to provide an implementation. A Java EE transaction manager can enlist multiple resources in a single transaction. If you work with several databases (or more than one resource), you probably want a two-phase commit protocol to guarantee atomicity of a transaction across resource boundaries. In such a scenario, Hibernate is configured with several SessionFactorys, one for each database, and their Sessions obtain managed database connections that all participate in the same system transaction. The quality of JTA implementations is usually higher compared to simple JDBC connection pools. Application servers and stand-alone JTA providers that are modules of application servers usually have had more testing in high-end systems with a large transaction volume. JTA providers don't add unnecessary overhead at runtime (a common misconception). The simple case (a single JDBC database) is handled as efficiently as with plain JDBC transactions. The connection pool managed behind a JTA service is probably much better software than a random connection pooling library you'd use with plain JDBC. Page 20 of 32 Transaction boundaries can be specified by programmatic calls, or by declarations to the container. The latter looks like one of the following annotations: @TransactionAttribute(TransactionAttributeType.REQUIRED) Here is a full table of them (in the book, this is on page 513, in the chapter on conversations) Conversation Management Conversation management is a way of understanding the persistence and session management policies associated with a sequence of operations on the database. There are no objects that are called “conversations” however. Conversations are controlled by creating and deletion of session objects, and by attachment and detachment of persistence objects to and from the session. An example would be to have a conversation that represents the sequence of steps to edit an object through a GUI, including the checking for conflicting changes by another user if the system is multi-user (as are all web-based applications). There are three typical control policies: No session or transaction Hibernate session–level User session-level Chapter 9 of Hibernate: a Developer’s Guide describes the following: Hibernate supports several different models for detecting this sort of versioning conflict (or optimistic locks). The versioning strategy uses a version column in the table. You can use either a version property tag or a timestamp property tag to indicate a version column for the class (see the appropriate tag for more information). When a record is updated, the versioning column is automatically updated as well. This versioning strategy is generally considered the best way to check for changes both for performance and for compatibility with database access that occurs outside of Hibernate. For example, you can simply issue a SELECT to obtain a record by id, and include the version column in the WHERE clause to indicate the specific record you wish to UDPATE; a failure to update is an easy way to detect Page 21 of 32 that the record is not properly synchronized. This is precisely the functionality as provided by the StaleObjectException. The dirty strategy only compares the columns that need to be updated. For example, let's say you load a Cat object, with a name ("Tom"), weight, and color. You change the name to "Bob" and want to save the change. Hibernate will verify that the current Cat name is "Tom" before updating the name to "Bob." This is computationally intensive compared to the versioning strategy, but can be useful in situations in which a version column is not feasible. The all strategy compares all the columns, verifying that the entire Cat is as it was when loaded before saving. Using the Cat example in the preceding paragraph, Hibernate will verify that the name, weight, and color are as loaded before persisting the change to the name. While more secure than the dirty strategy, this strategy, too, is more computationally intensive. Finally, the none strategy can be used to ignore optimistic locking. Updated columns are updated, period. This obviously performs better than any other strategy but is likely to lead to problems if you have more than a single user updating related records. Generally speaking, using a versioning strategy to manage conflicts is recommended. The pessimistic model, unless very carefully managed, can lead to more problems than it solves, and the dirty and all mechanisms are not very highperformance. Modifying Objects Efficiently One could certainly persist each object in a tree or other graph of objects, by calling session.saveOrUpdate() on each one. However, this would be tedious, and it would place a burden on the programmer to keep track of which objects are changed, new, deleted from the graph, etc. Instead, Hibernate can carry out this traversal, and maintain transitive persistence. It will follow each association, according the cascade mode. These are annotated on each association, and have the following values: XML attribute Annotation Description None (Default) Hibernate ignores the association. saveupdate org.hibernate.annotations.CascadeType.SAVE_UPDATE Hibernate navigates the association when the Session is flushed and when an object is passed to save() or update(), and saves newly instantiated transient instances and persist changes to detached instances. persist javax.persistence.CascadeType.PERSIST Hibernate makes any associated transient instance persistent when an object is passed to persist(). If you use native Hibernate, cascading occurs only at call-time. If you use the EntityManager module, this operation is cascaded when the persistence context is flushed. merge Javax.persistence.CascadeType.MERGE Hibernate navigates the association and merges the associated detached instances with equivalent persistent instances when an object is passed to merge(). Reachable transient instances are made persistent. delete org.hibernate.annotations.CascadeType.DELETE Hibernate navigates the association and deletes associated persistent instances when an object is passed to delete() or remove(). remove javax.persistence.CascadeType.REMOVE This option enables cascading deletion to associated persistent instances when an object is passed to remove() or delete(). lock org.hibernate.annotations.CascadeType.LOCK This option cascades the lock() operation to associated instances, reattaching them to the persistence context if the objects are detached. Note that the LockMode isn't cascaded; Hibernate assumes that you don't want pessimistic locks on associated objects—for example, because a pessimistic lock on the root object is good enough to avoid concurrent modification. replicate org.hibernate.annotations.CascadeType.REPLICATE Hibernate navigates the association and cascades the replicate() operation to associated objects. evict Page 22 of 32 org.hibernate.annotations.CascadeType.EVICT Hibernate evicts associated objects from the persistence context when an object is passed to evict() on the Hibernate XML attribute Annotation Description Session. refresh javax.persistence.CascadeType.REFRESH Hibernate rereads the state of associated objects from the database when an object is passed to refresh(). all javax.persistence.CascadeType.ALL This setting includes and enables all cascading options listed previously. deleteorphan org.hibernate.annotations.CascadeType.DELETE_ORPHAN This extra and special setting enables deletion of associated objects when they're removed from the association, that is, from a collection. If you enable this setting on an entity collection, you're telling Hibernate that the associated objects don't have shared references and can be safely deleted when a reference is removed from the collection. Examples Many to one @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE } ) @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE) @JoinColumn(name = "organizationtype_id", nullable = false) @ForeignKey(name = "FK_ORG_ORGTYPE") public OrganizationType getOrganizationType() { return organizationType; } public void setOrganizationType(OrganizationType organizationType) { this.organizationType = organizationType; } One to Many @OneToMany(mappedBy="organization", cascade=CascadeType.ALL, fetch=FetchType.LAZY) @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN) public List<Facility> getFacilities() { return facilities; } public void setFacilities(List<Facility> facilities) { this.facilities = facilities; } Here is the other side of the One to Many @ManyToOne() @JoinColumn(name="organization_id", nullable=false) public Organization getOrganization() { return organization; } public void setOrganization(Organization organization) { this.organization = organization; } Queries and Criteria While we will later see an approach to querying objects using a SQL-like query language, the simplest approach to fetch that uses an object-oriented interface and doesn’t require learning a query language is the Criteria class. (Note that the “Java Persistence with Hibernate” book focuses on the SQL-like query language before discussing the Criteria class. This appears to be for the benefit of EJB3-oriented and native SQL-oriented developers who are used to a statement-string-based representation. But we began to focus on object-oriented query languages several years back, and this document reflects such.) A Criteria object is a fetch specification which is built, restriction clause by restriction clause, using an object-oriented API. Here is an example: public static List getTracks(Time length) { Criteria crit = session.createCriteria(Track.class); Page 23 of 32 crit.add(Restrictions.eq(“categoryId”, 456); crit.add(Restrictions.le(“playTime”, length); crit.addOrder(Order.asc(“title”)); return crit.list(); } (Note that Restrictions has replaced the semi-deprecated class Expression. The example above is correct). From this example, you can conclude that an object-oriented fetch specification starts with the class to be fetched, which in turn must have been field-mapped. Then we add material for the specific field-level restrictions. Also, we added information about the ordering of results. The Criteria object is executed using one of the two routines: Object result = criteria.uniqueResult(); // Throws Hibernate exception // if more than 1 match for // criteria List list = criteria.list(); The Criteria object is one of the most useful pieces in Hibernate, as many of our programs (particularly on the Summary screens) need to programmatically construct restriction specifications. It is better than the string-building approach that we used with O/R mapping tools that didn’t have this facility. This also relates to the topic of when to use EJB3/JPA vs. when to use Hibernate: you may want to use Hibernate in this case, since the API-based Criteria building facilities are not present in JPA as of its current version. Further discussion of how to use the Criteria object follows. Since the Criteria is based on a target class, the fields that are being restricted on are directly in the target class. In order to add restrictions on subobjects, first build a subcriteria, as in: List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "F%") ) .createCriteria("kittens") .add( Restrictions.like("name", "F%") ) .list(); Note that the second createCriteria() returns a new instance of Criteria, which refers to the elements of the kittens collection. From a source-code perspective, this might be clearer as: Criteria crit1 = sess.createCriteria(Cat.class); crit1.add( Restrictions.like("name", "F%") ); Criteria crit2 = crit1.createCriteria("kittens"); crit2.add( Restrictions.like("name", "F%") ); List cats = crit1.list(); The following, alternate form is useful in certain circumstances. List cats = sess.createCriteria(Cat.class) .createAlias("kittens", "kt") .createAlias("mate", "mt") .add( Restrictions.eqProperty("kt.name", "mt.name") ) .list(); Where createAlias() does not create a new instance of Criteria, instead this is similar to creating aliases for tables in the SQL expression. Page 24 of 32 Both the createAlias form and the creation of subcriteria allow for the specification of the join type. By default this an inner join, but it can be changed to a left join using CriteriaSpecification.LEFT_JOIN. There are also facilities for creating “And” and “Or” grouping of restrictions, as in: Criteria crit = session.createCriteria(Track.class); Disjunction any = Restrictions.disjunction(); any.add(Restrictions.le(“playtime”, length)); any.add(Restrictions.like(“title”, “%A%”)); crit.add(any); Then there is a SQLRestriction facility, which allows a SQL restriction to be added to the where statement. Criteria crit = session.createCriteria(Track.class); crit.add(Restrictions.sqlRestriction (“’100’ > all (select b.AMOUNT from BID b where b.ITEM_ID = 456)”; Chapter 15 of the “Java Persistence in Action” book explains more of this. In addition, there are facilities to specify sort order in the Criteria object. This again is often used in Summary or reporting screens. Finally, there is a “query by example” facility. This works by creating a Criteria object, then creating an example object and adding it to the criteria. Here is an example: public List findUsersByExample(User u) { Criteria crit = session.createCriteria(User.class); Example e = Example.create(u); e.ignoreCase(); e.excludeProperty(“password”); crit.add(e); return crit.list(); } The benefit of this approach is that one could also add sort ordering conditions to the criteria before the call to crit.list(). One gotcha that we have seen here is that Hibernate’s query by example facility only generates restrictions on the nonid fields on the template object. It also skips the association fields. Advanced Queries and Criteria Reporting queries are a different way to use Hibernate Criteria objects. You can select exactly which objects or properties of objects you need in the query result and how you possibility want to aggregate and group results for a report. Reporting queries are described through Criteria objects in a very similar, with the ability to specify join and sorts, but they return field values rather than Java objects. A reporting query will have a projection specified on the Criteria object. The following criteria query (from the Hibernate book) returns only the identifier values of the items session.createCriteria(Item.class) .add( Restrictions.gt(“endDate”, new Date()), .setProjection( Projections.id() ); The trick here is the setProjection() method, which changes the Criteria object into a reporting query. While id() is a built-in function in the Projections class, there is another that will find a named field: Page 25 of 32 session.createCriteria(Item.class) .add( Restrictions.gt(“endDate”, new Date()), .setProjection( Projections.projectionList. .add(Projections.id() ) .add(Projections.property(“description”) ) .add(Projections.property(“initialPrice”)); Note that even if projections are added to the subcriteria, they are actually added to the main criteria object. Hence, if they wish to refer to fields in the join specified by the subcriteria, they must use a field name path that includes an alias. The result of a projection-based query are a set of Object[] rows, rather than objects of a specific Java class. However, this can be changed by using the ResultTransformer called AliasToBeanResultTransformer, which takes a Java class as its argument. Aggregation and grouping can also be carried out through additional modifiers on the setProjection() method’s arguments. For instance, you can add Projections.groupProperty(“u.userName”), Projections.count(“id”), Projections.avg(“amount”), Projections.min(“cost”), etc. The effect of adding the projections is to add a set of projection clauses to the end of the SQL statement (such as “group by”). The result of using this query is set of row of Object arrays that are laid out just as the grid-like table would be directly from the database. There is no hierarchy of rows to indicate groups, etc. This means, however, that if we want to display a set of raw data records as well as the groups and aggregations, we need to make two queries (most of the reporting engines are doing this behind the scenes). However, the API provided by Hibernate is a much more economical way to create the SQL statement than writing your own SQLClause builder. Using HQL Now we turn to the string-based representation of a query, called HQL. The simplest form of a query is a Query object, which takes an HQL expression. HQL is like SQL, but is more tuned to the objects that are mapped to the tables. For instance, you use Java class names instead of table names. Examples of using Query objects are: Query tenantQuery = session.createQuery("from dto.Tenant as tenant"); A query is carried out by calling its “list” method. This returns a java.util.List object, which can be iterated over. The HQL of a query can be parameterized, either by position or by keyword. Here is an example of one by position: Query query = session.createQuery (“from Item item where item.description like ? and item.type = ?”); query.setString(0, “northern”); query.setInteger(1, 40); Here is one by keyword: Query query = session.createQuery (“from Item item where item.description like :desc and item.type = :type”); query.setString(“description”, “northern”); query.setInteger(“type”, 40); The query string of HQL can be located in the application program, or it can be a named query in the Hibernate mapping file. An example would be: Page 26 of 32 <query name=”findItemsByDescription”> <![CDATA[from Item item where item.description like :description]]> </query> A query can be evaluated to return a list or a single object. Here is an example of each: The Query object (like the Criteria object) is executed using one of the two routines: Object result = query.uniqueResult(); // Throws Hibernate exception // if more than 1 match for // criteria List list = query.list(); Lazy and Non-Lazy Loading Another important concept is Lazy and non-Lazy loading of related records. By default, Hibernate never loads data that you didn’t ask for. You can either ask for this in the master configuration file, or within each query criteria. An important content is that of lazy references, which allow Hibernate to fetch an object that is associated to other objects (including child objects), and not fetch the child objects until they are referred to by the application code. However, this means that the session object that was used for the query of the original object must still be open, as Hibernate will use it to fetch on demand. This means that application designers must plan for the sessions to be longlived, or determine a fetch strategy of marking some references lazy=“false” so that all needed objects are provided. The lazy fetch mode is specified in the mapping file. This is discussed further below. Cache Management Cache Providers As we mentioned earlier, caching is a common method used to improve application performance. Caching can be as simple as having a class store frequently used data, or a cache can be distributed among multiple computers. The logic used by caches can also vary widely, but most use a simple least recently used (LRU) algorithm to determine which objects should be removed from the cache after a configurable amount of time. Before you get confused, let's clarify the difference between the Session–level cache, also called the first–level cache, and what this section covers. The Session–level cache stores object instances for the lifetime of a given Session instance. The caching services described in this section cache data outside of the lifetime of a given Session. Another way to think about the difference is that the Session cache is like a transactional cache that only caches the data needed for a given operation or set of operations, whereas a second–level cache is an application-wide cache. By default, Hibernate supports four different caching services, listed in table 2. EHCache (Easy Hibernate Cache) is the default service. If you prefer to use an alternative cache, you need to set the cache.provider_class property in the hibernate.cfg.xml file: <property name="cache.provider_class"> org.hibernate.cache.OSCacheProvider </property> This snippet sets the cache provider to the OSCache caching service. Table 2: Caching Services Supported by Hibernate Caching Service Provider Class Type EHCache org.hibernate.cache.EhCacheProvider Memory,disk OSCache org.hibernate.cache.OSCacheProvider Memory,disk Page 27 of 32 SwarmCache org.hibernate.cache.SwarmCacheProvider Clustered TreeCache org.hibernate.cache.TreeCacheProvider Clustered The caching services support the caching of classes as well as collections belonging to persistent classes. For instance, suppose you have a large number of Attendee instances associated with a particular Event instance. Instead of repeatedly fetching the collection of Attendees, you can cache it. Caching for classes and collections is configured in the mapping files, with the cache element: <class name="Event"table="events"> <cache usage="read-write"/> ... </class> Collections can also be cached: <set name="attendees"> <cache usage="read-write"/> ... </set> Once you've chosen a caching service, what do you, the developer, need to do differently to take advantage of cached objects? Thankfully, you don't have to do anything. Hibernate works with the cache behind the scenes, so concerns about retrieving an outdated object from the cache can be avoided. You only need to select the correct value for the usage attribute. The usage attribute specifies the caching concurrency strategy used by the underlying caching service. The previous configuration sets the usage to read–write, which is desirable if your application needs to update data. Alternatively, you may use the nonstrict–read–write strategy if it's unlikely two separate transaction threads could update the same object. If a persistent object is never updated, only read from the database, you may specify set usage to read-only. Some caching services, such as the JBoss TreeCache, use transactions to batch multiple operations and perform the batch as a single unit of work. If you choose to use a transactional cache, you may set the usage attribute to transactional to take advantage of this feature. If you happen to be using a transactional cache, you'll also need to set the transaction.manager_lookup_class mentioned in the previous section. The supported caching strategies differ based on the service used. Table 3 shows the supported strategies. Table 3: Supported Caching Service Strategies Caching Service Readonly Readwrite Nonstrict-readTransactional write EHCache Y Y Y N OSCache Y Y Y N SwarmCache Y Y Y N TreeCache Y N N Y Clearly, the caching service you choose will depend on your application requirements and environment. Configuring EHCache By now you're probably tired of reading about configuring Hibernate, but EHCache is pretty simple. It's a single XML file, placed in a directory listed in your classpath. You'll probably want to put the ehcache.xml file in the same directory as the hibernate.cfg.xml file. Page 28 of 32 <ehcache> <diskStore path="java.io.tmp"/> <defaultCache maxElementsInMemory="10" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"/> <cache name="com.manning.hq.ch03.Event" maxElementsInMemory="20" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="180" overflowToDisk="true"/> </ehcache> In this example, the diskStore property sets the location of the disk cache store. Then, the listing declares two caches. The defaultCache element contains the settings for all cached objects that don't have a specific cache element: the number of cached objects held in memory, whether objects in the cache expire (if eternal is true, then objects don't expire), the number of seconds an object should remain the cache after it was last accessed, the number of seconds an object should remain in the cache after it was created, and whether objects exceeding maxElementsInMemory should be spooled to the diskStore. Next, for custom settings based on the class, the code defines a cache element with the fully qualified class name listed in the name attribute. (This listing only demonstrates a subset of the available configuration for EHCache. Please refer to the documentation found at http:// ehcache.sf.net for more information.). Using Hibernate-Managed JDBC connections The sample configuration file in below uses Hibernate-managed JDBC connections. You would typically encounter this configuration in a non-managed environment, such as a standalone application. <?xml version="1.0"> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.username">uid</property> <property name="connection.password">pwd</property> <property name="connection.url">jdbc:mysql://localhost/db</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <mapping resource="com/manning/hq/ch03/Event.hbm.xml"/> <mapping resource="com/manning/hq/ch03/Location.hbm.xml"/> <mapping resource="com/manning/hq/ch03/Speaker.hbm.xml"/> <mapping resource="com/manning/hq/ch03/Attendee.hbm.xml"/> </session-factory> </hibernate-configuration> To use Hibernate-provided JDBC connections, the configuration file requires the following five properties: connection.driver_class -The JDBC connection class for the specific database connection.url -The full JDBC URL to the database connection.username -The username used to connect to the database connection.password -The password used to authenticate the username dialect -The name of the SQL dialect for the database The connection properties are common to any Java developer who has worked with JDBC in the past. Since you're not specifying a connection pool, which we cover later in this chapter, Hibernate uses its own rudimentary connectionpooling mechanism. The internal pool is fine for basic testing, but you shouldn't use it in production. Page 29 of 32 The dialect property tells Hibernate which SQL dialect to use for certain operations. Although not strictly required, it should be used to ensure Hibernate Query Language (HQL) statements are correctly converted into the proper SQL dialect for the underlying database. The dialect property tells the framework whether the given database supports identity columns, altering relational tables, and unique indexes, among other database-specific details. Hibernate ships with more than 20 SQL dialects, supporting each of the major database vendors, including Oracle, DB2, MySQL, and PostgreSQL. Hibernate also needs to know the location and names of the mapping files describing the persistent classes. The mapping element provides the name of each mapping file as well as its location relative to the application classpath. There are different methods of configuring the location of the mapping file, which we'll examine later. Connection Pools Connection pools are a common way to improve application performance. Rather than opening a separate connection to the database for each request, the connection pool maintains a collection of open database connections that are reused. Application servers often provide their own connection pools using a JNDI DataSource, which Hibernate can take advantage of when configured to use a DataSource. If you're running a standalone application or your application server doesn't support connection pools, Hibernate supports three connection pooling services: C3P0, Apache's DBCP library, and Proxool. C3P0 is distributed with Hibernate; the other two are available as separate distributions. When you choose a connection pooling service, you must configure it for your environment. Hibernate supports configuring connection pools from the hibernate.cfg.xml file. The connection.provider_class property sets the pooling implementation: <property name="connection.provider_class"> org.hibernate.connection.C3P0ConnectionProvider </property> Once the provider class is set, the specific properties for the pooling service can also be configured from the hibernate.cfg.xml file: <property name="c3p0.minPoolSize"> 5 </property> ... <property name="c3p0.timeout"> 1000 </property> As you can see, the prefix for the C3P0 configuration parameters is c3p0. Similarly, the prefixes for DBCP and Proxool are dbcp and proxool, respectively. Specific configuration parameters for each pooling service are available in the documentation with each service. Table 1 lists information for the supported connection pools. Hibernate ships with a basic connection pool suitable for development and testing purposes. However, it should not be used in production. You should always use one of the available connection pooling services, like C3P0, when deploying your application to production. If your preferred connection pool API isn't currently supported by Hibernate, you can add support for it by implementing the org.hibernate.connection.ConnectionProvider interface. Implementing the interface is straightforward. Pooling Service C3PO Provider Class org.hibernate.connecorg.hibernate.connecorg.hibernate.connection.C3P0ConnectionProvider tion.ProxoolConnectionProvider tion.DBCPConnectionProvider Page 30 of 32 Apache DBCP Proxool Configuration c3p0 Prefix Dbcp proxool There isn't much to using a connection pool, since Hibernate does most of the work behind the scenes. Hibernate Tools Working with Hibernate is very easy and developers enjoy using the APIs and the query language. Even creating mapping metadata is not an overly complex task once you've mastered the basics. Hibernate Tools makes working with Hibernate or EJB 3.0 persistence even more pleasant. Hibernate Tools is an entirely new toolset for Hibernate3, implemented as an integrated suite of Eclipse plugins, together with a unified Ant task for integration into the build cycle. Hibernate Tools is a core component of JBoss Tools (see our document “Notes on JBoss Tools”). How to install: In Eclipse, select Help / Software Updates / Find and Install Select "Search for new features to install" and hit Next Select "New Remote Site..." For Name enter: Hibernate Tools For URL enter: http://download.jboss.org/jbosstools/updates/stable Click OK to save the new site Check the box next to the site you just added (Hibernate Tools) and click Finish Click arrow to expand Hibernate Tools Click arrow to expand JBoss Tools Development Release: <version> Check box next to Hibernate Tools (name may be slightly different) Select Next, and accept the license agreement and Install All To use Hibernate Tools, go the New… menu and create Other…, then select Hibernate from the list of types, then expand out. The list will look like: We don’t generally do Reverse Engineering, so that isn’t too useful, and we don’t generate XML Mappings, so that isn’t useful. The option to create the Hibernate Configuration file could be useful, but we generally do it by hand instead. Other parts of the Hibernate Tools package are just a wrapper for the hbm2ddl facilities that are discussed above under “Programmatic Generation of Schema”. Actually, Hibernate Tools didn’t prove to be too critical for our work. Appendix A: Guide to the “Java Persistence using Hibernate” Book The book was written for Hibernate 3.2. It is organized as follows, with the most important chapters shown in bold. Part 1: Getting started with Hibernate and EJB 3.0 Page 31 of 32 Chapter 1: Introduces the object-relational mismatch and nature of solutions. Chapter 2: Example project and programs using Hibernate. Quite important, as it covers the current library set, an example problem, and setup. Chapter 3: Domain models and metadata. This introduces the concepts used in the mapping files. Page 138 discuses dynamic manipulation of the metadata. Part 2: Mapping Concepts and Strategies Chapter 4: Mapping persistence classes Chapter 5: Inheritance and custom types Chapter 6: Mapping collections and entity association Chapter 7: Advanced entity association mappings Chapter 8: Legacy databases and custom SQL Part 3: Conversational Object Processing Chapter 9: Working with objects. This returns to the run-time API, such as the save, query, and transaction facilities. Chapter 10: Transactions and concurrency. Chapter 11: Implementing conversations. This deals with long-running transactions, called “conversations”. Chapter 12: Modifying objects efficiently. Chapter 13: Optimizing fetch and caching: Covers how to tell Hibernate when to use joins and when to use multiple queries. The material on caching follows the material on fetch optimization. Chapter 14: Querying with HQL and JPA QL: important, as it covers how to express queries in HQL. It also talked about the reporting query facility. Chapter 15: Advanced query options. This chapter is the documentation for the Criteria object and related interfaces, which were quite important in writing filter expressions and similar tools in an object-oriented fashion. Chapter 16: Creating and testing layered applications. This was quite useful as it talked about Web applications, and the organization of DAO layers. Chapter 17: Introducing JBoss Seam. This chapter is a discussion of a very powerful application building framework. It is not specifically related to the prior chapters. There are now entire books just on Seam, so this isn’t one of the most important chapters, though Seam itself worth treating as important. Page 32 of 32