Hibernate Tutorial - Java Code Geeks

Transcription

Hibernate TutorialiHibernate Tutorial

Hibernate TutorialiiContents1Introduction12Project setup23Basics33.1SessionFactory and Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .33.2Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .53.3Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .54Inheritance5Relationships8145.1OneToOne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145.2OneToMany . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175.3ManyToMany . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205.4Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236User-defined Data Types257Interceptors288Download30

Hibernate TutorialCopyright (c) Exelixis Media P.C., 2015All rights reserved. Without limiting the rights undercopyright reserved above, no part of this publicationmay be reproduced, stored or introduced into a retrieval system, ortransmitted, in any form or by any means (electronic, mechanical,photocopying, recording or otherwise), without the prior writtenpermission of the copyright owner.iii

Hibernate TutorialivPrefaceibernate ORM (Hibernate in short) is an object-relational mapping framework, facilitating the conversion of an object-orienteddomain model to a traditional relational database. Hibernate solves the object-relational impedance mismatch problems byreplacing direct persistence-related database accesses with high-level object handling functions.Hibernate is one of the most popular Java frameworks out there. For this reason we have provided an abundance of tutorials hereat Java Code Geeks, most of which can be found here: als/enterprise-javatutorials/#HibernateNow, we wanted to create a standalone, reference post to provide a framework on how to work with Hibernate and help youquickly kick-start your Hibernate applications. Enjoy!

Hibernate TutorialvAbout the AuthorMartin is a software engineer with more than 10 years of experience in software development. He has been involved in different positions in application development in a variety of software projects ranging from reusable software components, mobileapplications over fat-client GUI projects up to larg-scale, clustered enterprise applications with real-time requirements.After finishing his studies of computer science with a diploma, Martin worked as a Java developer and consultant for internationaloperating insurance companies. Later on he designed and implemented web applications and fat-client applications for companieson the energy market. Currently Martin works for an international operating company in the Java EE domain and is concernedin his day-to-day work with larg-scale big data systems.His current interests include Java EE, web applications with focus on HTML5 and performance optimizations. When timepermits, he works on open source projects, some of them can be found at this github account. Martin is blogging at Martin’sDeveloper World.

Hibernate Tutorial1 / 30Chapter 1IntroductionHibernate is one of the most popular Object/Relational Mapping (ORM) framework in the Java world. It allows developers tomap the object structures of normal Java classes to the relational structure of a database. With the help of an ORM framework thework to store data from object instances in memory to a persistent data store and load them back into the same object structurebecomes significantly easier.At the same time ORM solutions like Hibernate aim to abstract from the specific product used to store the data. This allows usingthe same Java code with different database products without the need to write code that handles the subtle differences betweenthe supported products.Hibernate is also a JPA provider, that means it implements the Java Persistence API (JPA). JPA is a vendor independent specification for mapping Java objects to the tables of relational databases. As another article of the Ultimate series already addressesthe JPA, this article focuses on Hibernate and therefore does not use the JPA annotations but rather the Hibernate specific configuration files.Hibernate consists of three different components: Entities: The classes that are mapped by Hibernate to the tables of a relational database system are simple Java classes (PlainOld Java Objects). Object-relational metadata: The information how to map the entities to the relational database is either provided by annotations (since Java 1.5) or by legacy XML-based configuration files. The information in these files is used at runtime to performthe mapping to the data store and back to the Java objects. Hibernate Query Language (HQL): When using Hibernate, queries send to the database do not have to be formulated innative SQL but can be specified using Hibernate’s query language. As these queries are translated at runtime into the currentlyused dialect of the chose product, queries formulated in HQL are independent from the SQL dialect of a specific vendor.In this tutorial we are going through different aspects of the framework and will develop a simple Java SE application that storesand retrieves data in/from a relational database. We will use the following libraries/environments: maven 3.0 as build environment Hibernate(4.3.8.Final) H2 as relational database (1.3.176)

Hibernate Tutorial2 / 30Chapter 2Project setupAs a first step we will create a simple maven project on the command line:mvn archetype:create -DgroupId com.javacodegeeks.ultimate -DartifactId hibernateThis command will create the following structure in the file system: - ‘--src -- main ‘-- java ‘-- com ‘-- javacodegeeks ‘-- ultimate‘-- test ‘-- java ‘-- com ‘-- javacodegeeks ‘-- ultimatepom.xmlThe libraries our implementation depends on are added to the dependencies section of the pom.xml file in the following way: properties h2.version 1.3.176 /h2.version hibernate.version 4.3.8.Final /hibernate.version /properties dependencies dependency groupId com.h2database /groupId artifactId h2 /artifactId version {h2.version} /version /dependency dependency groupId org.hibernate /groupId artifactId hibernate-core /artifactId version {hibernate.version} /version /dependency /dependencies To get a better overview of the separate versions, we define each version as a maven property and reference it later on in thedependencies section.

Hibernate Tutorial3 / 30Chapter 3Basics3.1SessionFactory and SessionNow we cat start to implement our first O/R mapping. Let’s start with a simple class that provides a run() method that isinvoked in the application’s main method:public class Main {private static final Logger LOGGER Logger.getLogger("Hibernate-Tutorial");public static void main(String[] args) {Main main new Main();main.run();}public void run() {SessionFactory sessionFactory null;Session session null;try {Configuration configuration new .cfg.xml");ServiceRegistry serviceRegistry new figuration. getProperties()).build();sessionFactory configuration.buildSessionFactory(serviceRegistry) ;session );} catch (Exception e) {LOGGER.log(Level.SEVERE, e.getMessage(), e);} finally {if (session ! null) {session.close();}if (sessionFactory ! null) {sessionFactory.close();}}}.The run() method creates a new instance of the class org.hibernate.cfg.Configuration that is subsequently configured using the XML file hibernate.cfg.xml. Placing the configuration file in the folder src/main/resources ofour project lets maven put it to the root of the created jar file. This way the file is found at runtime on the classpath.

Hibernate Tutorial4 / 30As a second step the run() method constructs a ServiceRegistry that uses the previously loaded configuration. Aninstance of this ServiceRegistry can now be passed as an argument to the method buildSessionFactroy() of theConfiguration. This SessionFactory can now be used to obtain the session needed to store and load entities to theunderlying data store.The configuration file hibernate.cfg.xml has the following content: ?xml version ’1.0’ encoding ’utf-8’? !DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD nfiguration-3.0.dtd" hibernate-configuration session-factory property name "connection.driver class" org.h2.Driver /property property name "connection.url" jdbc:h2: /hibernate;AUTOCOMMIT OFF /property property name "connection.username" /property property name "connection.password" /property property name "connection.pool size" 1 /property property name "dialect" org.hibernate.dialect.H2Dialect /property property name "current session context class" thread /property property name "cache.provider class" org.hibernate.cache.internal.NoCacheProvider /property property name "show sql" true /property property name "format sql" true /property property name "hbm2ddl.auto" create /property mapping resource "Project.hbm.xml"/ /session-factory /hibernate-configuration As we see from the example above, the configuration file defines a set of properties for the session factory. The first propertyconnection.driver class specifies the database driver that should be used. In our example this is the driver for the H2database. Through the property connection.url, the JDBC-URL is specified. In our case defines that we want to use h2and that the single database file where H2 stores its data should be located in the home directory of the user and should be namedhibernate ( /hibernate). As we want to commit our transactions in the example code on our own, we also define the H2specific configuration option AUTOCOMMIT OFF.Next the configuration file defines the username and password for the database connection as well as the size of the connectionpool. Our sample application just executes code in one single thread, therefore we can set the pool size to one. In cases of anapplication that has to deal with multiple threads and users, an appropriate pool size has to be chosen.The property dialect specifies a Java class that performs the translation into the database specific SQL dialect.As of version 3.1, Hibernate provides a method named SessionFactory.getCurrentSession() that allows the developer to obtain a reference to the current session. With the configuration property current session context class itcan be configured where Hibernate should obtain this session from. The default value for this property is jta meaning that Hibernate obtains the session from the underlying Java Transaction API (JTA). As we are not using JTA in this sample, we instructHibernate with the configuration value thread to store and retrieve the session to/from the current thread.For the sake of simplicity, we do not want to utilize an entity cache. Hence we set the property cache.provider class toorg.hibernate.cache.internal.NoCacheProvider.The following two options tell Hibernate to print out each SQL statement to the console and to format it for better readability.In order to relieve us for development purposes from the burden to create the schema manually, we instruct Hibernate with theoption hbm2ddl.auto set to create to create all tables during startup.Last but not least we define a mapping resource file that contains all the mapping information for our application. The content ofthis file will be explained in the following sections.As mentioned above, the session is used to communicate with the data store and actually represents a JDBC connection. Thismeans all interaction with the connection is done through the session. It is single-threaded and provides a cache for all objectsit has up to now worked with. Therefore each thread in the application should work with its own session that it obtains from thesession factory.

Hibernate Tutorial5 / 30In contrast to the session, the session factory is thread-safe and provides an immutable cache for the define mappings. For eachdatabase there is exactly one session factory. Optionally, the session factory can provide in addition to the session’s first levelcache an application wide second level cache.3.2TransactionsIn the hibernate.cfg.xml configuration file we have configured to manage transactions on our own. Hence we have tomanually start and commit or rollback every transaction. The following code demonstrates how to obtain a new transaction fromthe session and how to start and commit it:try {Transaction transaction saction.commit();} catch (Exception e) {if (session.getTransaction().isActive()) {session.getTransaction().rollback();}throw e;}In the first step we call getTransaction() in order to retrieve a reference for a new transaction. This transaction is immediately started by invoking the method begin() on it. If the following code proceeds without any exception, the transaction getscommitted. In case an exception occurred and the current transaction is active, the transaction is rolled back.As the code shown above is the same for all upcoming examples, it is not repeated in the exact form again and again. The stepsto refactor the code into a re-usable form, using for example the template pattern, are left for the reader.3.3TablesNow that we have learned about session factories, sessions and transactions, it is time to start with the first class mapping. Inorder to have an easy start, we choose a simple class with only a few simple attributes:public class Person {private Long id;private String firstName;private String lastName;public Long getId() {return id;}public void setId(Long id) {this.id id;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName firstName;}public String getLastName() {return lastName;}

Hibernate Tutorial6 / 30public void setLastName(String lastName) {this.lastName lastName;}}The Person class comes with two attributes to store the name of a person (firstName and lastName). The field id is usedto store the object’s unique identifier as a long value. In this tutorial we are going to use mapping files instead of annotations,hence we specify the mapping of this class to the table T PERSON as follows: ?xml version "1.0"? !DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD pping-3.0.dtd" hibernate-mapping package "hibernate.entity" class name "Person" table "T PERSON" id name "id" column "ID" generator class "native"/ /id property name "firstName" column "FIRST NAME"/ property name "lastName" column "LAST NAME"/ /class /hibernate-mapping The XML element hibernate-mapping is used to define the package our entities reside in (here: hibernate.entity).Inside this element one class element is provided for each class that should be mapped to a table in the database.The id element specifies the name (name) of the class’s field that holds the unique identifier and the name of the column thisvalue is stored in (ID). With its child element generator Hibernate gets to know how to create the unique identifier for eachentity. Next to the value native shown above, Hibernate supports a long list of different strategies.The native strategy just chooses the best strategy for the used database product. Hence this strategy can be applied for differentproducts. Other possible values are for example: sequence (uses a sequence in the database), uuid (generates a 128-bit UUID)and assigned (lets the application assign the value on its own). Beyond the pre-defined strategies it is possible to implementa custom strategy by implementing the interface org.hibernate.id.IdentifierGenerator.The fields firstName and lastName are mapped to the columns FIRST NAME and LAST NAME by using the XML elementproperty. The attributes name and column define the field’s name in the class and the column, respectively.The following code shows exemplary how to store a person in the database:private void persistPerson(Session session) throws Exception {try {Transaction transaction n person new .commit();} catch (Exception e) {if (session.getTransaction().isActive()) {session.getTransaction().rollback();}throw e;}}Next to the code to handle the transaction it creates a new instance of the class Person and assigns two values to the fieldsfirstName and lastName. Finally it stores the person in the database by invoking the session’s method save().When we execute the code above, the following SQL statements are printed on the console:

Hibernate Tutorial7 / 30Hibernate:drop table T PERSON if existsHibernate:create table T PERSON (ID bigint generated by default as identity,FIRST NAME varchar(255),LAST NAME varchar(255),primary key (ID))Hibernate:insertintoT PERSON(ID, firstName, lastName, ID ID CARD)values(null, ?, ?, ?)As we have chosen to let Hibernate drop and create the tables on startup, the first statements printed out are the drop table andcreate table statements. We can also see the three columns ID, FIRST NAME and LAST NAME of the table T PERSONas well as the definition of the primary key (here: ID).After the table has been created, the invocation of session.save() issues an insert statement to the database. As Hibernate internally uses a PreparedStatement, we do not see the values on the console. In case you also want to see thevalues that are bound to the parameters of the PreparedStatement, you can set the logging level for the logger org.hibernate.type to FINEST. This is done within a file called logging.properties with the following content (thepath to the file can be given for example as a system property -Djava.util.logging.config.file src/main/resources/logging.properties):.handlers java.util.logging.ConsoleHandler.level INFOjava.util.logging.ConsoleHandler.level ALLjava.util.logging.ConsoleHandler.formatter .level FINESTorg.hibernate.type.level FINESTSetting the logger org.hibernate.SQL has the same effect as setting the property show sql in the Hibernate configurationfile to true.Now you can see the following output and therewith the actual values on the console:DEBUG:insertintoT PERSON(ID, FIRST NAME,values(null, ?, ?, ?)TRACE: binding parameterTRACE: binding parameterTRACE: binding parameterLAST NAME, ID ID CARD)[1] as [VARCHAR] - [Homer][2] as [VARCHAR] - [Simpson][3] as [BIGINT] - [null]

Hibernate Tutorial8 / 30Chapter 4InheritanceAn interesting feature of O/R mapping solutions like Hibernate is the usage of inheritance. The user can chose how to mapsuperclass and subclass to the tables of a relational database. Hibernate supports the following mapping strategies: Single table per class: Both superclass and subclass are mapped to the same table. An additional column marks whether therow is an instance of the superclass or subclass and fields that are not present in the superclass are left empty. Joined subclass: This strategy uses a separate table for each class whereas the table for the subclass only stores the fields thatare not present in the superclass. To retrieve all values for an instance of the subclass, a join between the two tables has to beperformed. Table per class: This strategy also uses a separate table for each class but stores in the table for the subclass also the fields ofthe superclass. With this strategy one row in the subclass table contains all values and in order to retrieve all values no joinstatement is necessary.The approach we are going to investigate is the "Single Table per class" approach. As a subclass of person we choose the classGeek:public class Geek extends Person {private String favouriteProgrammingLanguage;public String getFavouriteProgrammingLanguage() {return favouriteProgrammingLanguage;}public void setFavouriteProgrammingLanguage(String favouriteProgrammingLanguage) {this.favouriteProgrammingLanguage favouriteProgrammingLanguage;}}The class extends the already known class Person and adds an additional field named favouriteProgrammingLanguage. The mapping file for this use case looks like the following one: ?xml version "1.0"? !DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD pping-3.0.dtd" hibernate-mapping package "hibernate.entity" class name "Person" table "T PERSON" id name "id" column "ID" generator class "native"/ /id discriminator column "PERSON TYPE" type "string"/

Hibernate Tutorial9 / 30 property name "firstName" column "FIRST NAME"/ property name "lastName" column "LAST NAME"/ subclass name "Geek" extends "Person" property name "favouriteProgrammingLanguage" column "FAV PROG LANG"/ /subclass /class /hibernate-mapping The first difference is the introduction of the discriminator column. As mentioned above this column stores the informationof which type the current instance is. In our case we call it PERSON TYPE and let for better readability a string denote the actualtype. Per default Hibernate takes just the class name in this case. To save storage one can also use a column of type integer.Beyond the discriminator we have also added the subclass element that informs Hibernate about the new Java class Geekand its field favouriteProgrammingLanguage which should be mapped to the column FAV PROG LANG.The following sample codes shows how to store instances of type Geek in the database:session.getTransaction().begin();Geek geek new ava");session.save(geek);geek new #");session.save(geek);geek new .commit();Executing the code shown above, leads to the following output:Hibernate:drop table T PERSON if existsHibernate:create table T PERSON (ID bigint generated by default as identity,PERSON TYPE varchar(255) not null,FIRST NAME varchar(255),LAST NAME varchar(255),FAV PROG LANG varchar(255),primary key (ID))Hibernate:insertintoT PERSON(ID, FIRST NAME, LAST NAME, FAV PROG LANG, PERSON TYPE)values(null, ?, ?, ?, ’hibernate.entity.Geek’)In contrast to the previous example the table T PERSON now contains the two new columns PERSON TYPE and FAV PROGLANG. The column PERSON TYPE contains the value hibernate.entity.Geek for geeks.In order to investigate the content of the T PERSON table, we can utilize the Shell application shipped within the H2 jar file: java -cp h2-1.3.176.jar org.h2.tools.Shell -url jdbc:h2: /hibernate.

Hibernate Tutorialsql ID 1 2 3 4 select * from t person;PERSON bernate.entity.Geekhibernate.entity.Geek10 / 30 FIRST NAMEHomerGavinThomasChristian LAST NAMESimpsonCoffeeMicroCup FAV PROG LANGnullJavaC#JavaAs discussed above, the column PERSON TYPE stores the type of the instance whereas the column FAV PROG LANG containsthe value null for instances of the superclass Person.Changing the mapping definition in a way that it looks like the following one, Hibernate will create for the superclass and thesubclass a separate table: ?xml version "1.0"? !DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD pping-3.0.dtd" hibernate-mapping package "hibernate.entity" class name "Person" table "T PERSON" id name "id" column "ID" generator class "native"/ /id property name "firstName" column "FIRST NAME"/ property name "lastName" column "LAST NAME"/ joined-subclass name "Geek" table "T GEEK" key column "ID PERSON"/ property name "favouriteProgrammingLanguage" column "FAV PROG LANG"/ /joined-subclass /class /hibernate-mapping The XML element joined-subclass tells Hibernate to create the table T GEEK for the subclass Geek with the additionalcolumn ID PERSON. This additional key column stores a foreign key to the table T PERSON in order to assign each row inT GEEK to its parent row in T PERSON.Using the Java code shown above to store a few geeks in the database, results in the following output on the console:Hibernate:drop table T GEEK if existsHibernate:drop table T PERSON if existsHibernate:create table T GEEK (ID PERSON bigint not null,FAV PROG LANG varchar(255),primary key (ID PERSON))Hibernate:create table T PERSON (ID bigint generated by default as identity,FIRST NAME varchar(255),LAST NAME varchar(255),primary key (ID))Hibernate:alter table T GEEKadd constraint FK p2ile8qooftvytnxnqtjkrbsaforeign key (ID PERSON)references T PERSON

Hibernate Tutorial11 / 30Now Hibernate creates two tables instead of one and defines a foreign key for the table T GEEK that references the table T PERSON. The table T GEEK consists of two columns: ID PERSON to reference the corresponding person and FAV PROG LANGto store the favorite programming language.Storing a geek in the database now consists of two insert statements:Hibernate:insertintoT PERSON(ID, FIRST NAME, LAST NAME, ID ID CARD)values(null, ?, ?, ?)Hibernate:insertintoT GEEK(FAV PROG LANG, ID PERSON)values(?, ?)The first statement inserts a new row into the table T PERSON, while the second one inserts a new row into the table T GEEK.The content of these two tables look afterwards like this:sql ID 1 2 3 4 select * from t person;FIRST NAME LAST NAMEHomer SimpsonGavin CoffeeThomas MicroChristian Cupsql selectID PERSON 2 3 4 * from t geek;FAV PROG LANGJavaC#JavaObviously the table T PERSON only stores the attributes of the superclass whereas the table T GEEK only stores the field valuesfor the subclass. The column ID PERSON references the corresponding row from the parent table.The next strategy under investigation is "table per class". Similar to the last strategy this one also creates a separate table for eachclass, but in contrast the table for the subclass contains also all columns of the superclass. Therewith one row in such a tablecontains all values to construct an instance of this type without the need to join additional data from the parent table. On hugedata set this can improve the performance of queries as joins need to find additionally the corresponding rows in the parent table.This additional lookup costs time that is circumvented with this approach.To use this strategy for the above use case, the mapping file can be rewritten like the following one: ?xml version "1.0"? !DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD pping-3.0.dtd" hibernate-mapping package "hibernate.entity" class name "Person" table "T PERSON" id name "id" column "ID" generator class "sequence"/ /id property name "firstName" column "FIRST NAME"/ property name "lastName" column "LAST NAME"/ union-subclass name "Geek" table "T GEEK" property name "favouriteProgrammingLanguage" column "FAV PROG LANG"/ /union-subclass

Hibernate Tutorial12 / 30 /class /hibernate-mapping The XML element union-subclass provides the name of the entity (Geek) as well as the name of the separate table(T GEEK) as attributes. As within the other approaches, the field favouriteProgrammingLanguage is declared as aproperty of the subclass.Another important change with regard to the other approaches is contained in the line that defines the id generator. As the otherapproaches use a native generator, which falls back on H2 to an identity column, this approach requires an id generator thatcreates identities that are unique for both tables (T PERSON and T GEEK).The identity column is just a special type of column that automatically creates for each row a new id. But with two tables wehave also two identity columns and therewith the ids in the T PERSON table can be the same as in the T GEEK table. Thisconflicts with the requirement that an entity of type Geek can be created just by reading one row of the table T GEEK and thatthe identifiers for all persons and geeks are unique. Therefore we are using a sequence instead of an identity column by switchingthe value for the class attribute from native to sequence.Now the DDL statements created by Hibernate look like the following ones:Hibernate:drop table T GEEK if existsHibernate:drop table T PERSON if existsHibernate:drop sequence if exists hibernate sequenceHibernate:create table T GEEK (ID bigint not null,FIRST NAME varchar(255),LAST NAME varchar(255),FAV PROG LANG varchar(255),primary key (ID))Hibernate:create table T PERSON (ID bigint not null,FIRST NAME varchar(255),LAST NAME varchar(255),primary key (ID))Hibernate:create sequence hibernate sequenceThe output above clearly demonstrates that the table T GEEK now contains next to FAV PROG LANG also the columns for thesuperclass (FIRST NAME and LAST NAME). The statements do not create a foreign key between the two tables. Please alsonote that now the column ID is no longer an identity column but that instead a sequence is created.The insertion of a person and a geek issues the following statements to the database:Hibernate:call next value for hibernate sequenceHibernate:insertintoT PERSON(FIRST NAME, LAST NAME, ID)values(?, ?, ?, ?)Hibernate:call next value for hibernate sequenceHi

In this tutorial we are going through different aspects of the framework and will develop a simple Java SE application that stores and retrieves data in/from a relational database. We will use the following libraries/environments: maven 3.0 as build environment Hibernate(4.3.8.Final) H2 as relational database (1.3.176)