Creating a Hibernate JPA project

exercise No. 2

Q:

This exercises focus on the Airline domain model. We provide a step by step development of a Java domain model based on using JPA annotations.

We create a Maven based project. In the current exercise we only map Airline instances completely ignoring all remaining model components.

  1. Be sure to configure the supplementary MI Maven archetypes in your Eclipse IDE.

  2. Choose the mi-maven-archetype-quickstart artifact and create a new project named Airline.

  3. Create an Airline @Entity class inside a xyz.model package:

    package de.hdm_stuttgart.mi.persist.airline.model;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    
    @Entity
    public class Airline {
       @Id
       @GeneratedValue
       Long id;
       String name;
       String icaoCode;
       
       public Airline(final String name, final String icaoCode) {
          this.name = name;
          this.icaoCode = icaoCode;
       }
       protected Airline(){}   
    }

    The three imports require additional libraries to be present. Using Maven this may be achieved by adding the following dependency to your project's pom.xml file:

    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>5.1.0.Final</version>
    </dependency>

    Why do we need protected Airline(){} ?

  4. Chapter 2 of [Bauer2015] provides hints starting a project. Rather than using the described more elaborate JTA based setup you may just want to follow a simpler JDBC based approach when defining a persistence unit in your project's src/main/resources/META-INF/persistence.xml file:

    <persistence
        version="2.1"
        xmlns="http://xmlns.jcp.org/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    
        <!-- 
             The <code>persistence.xml</code> file configures at least one persistence unit;
             each unit must have a unique name.
        -->
        <persistence-unit name="AirlinePU">
    
            <!-- A persistent unit has persistent (mapped) classes, you list them here. -->
            <class>de.hdm_stuttgart.mi.persist.airline.model.Airline</class>
    
            <!-- Hibernate can scan your classpath for mapped classes and add them automatically
                 to your persistence unit. This setting disables that feature. -->
            <exclude-unlisted-classes>true</exclude-unlisted-classes>
    
            <!-- Standard or vendor-specific options can be set as properties on a persistence unit.
                 Any standard properties have the <code>javax.persistence</code> name prefix, Hibernate's
                 settings use <code>hibernate</code> -->
            <properties>
                <!-- JDBC database connection parameter -->
                <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
                <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/hdm?useSSL=false"/>
                <property name="javax.persistence.jdbc.user" value="hdmuser"/>
                <property name="javax.persistence.jdbc.password" value="XYZ"/>
    
                <!-- The JPA engine should drop and re-create the SQL schema in the database
                     automatically when it boots. This is ideal for automated testing, when
                     you want to work with a clean database for every test run. -->
                <property
                    name="javax.persistence.schema-generation.database.action"
                    value="drop-and-create"/>
    
                <!-- When printing SQL in logs, let Hibernate format the SQL nicely and generate
                     comments into the SQL string so we know why Hibernate executed the SQL statement. -->
                <property name="hibernate.format_sql" value="true"/>
                <property name="hibernate.use_sql_comments" value="true"/>
    
                <!-- Disable Hibernate scanning completely, we also don't want any hbm.xml files
                     discovered and added automatically. -->
                <property name="hibernate.archive.autodetection" value="none"/>
    
            </properties>
        </persistence-unit>
    </persistence>

    Our persistence unit connecting to a Mysql database server requires another Maven dependency:

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.38</version>
    </dependency>
  5. Our main() class will just write a single Airline instance to the database server:

    package de.hdm_stuttgart.mi.persist.airline;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;
    
    import de.hdm_stuttgart.mi.persist.airline.model.Airline;
    
    public class CreateAirline {
    
       // This requires a corresponding entry <persistence-unit name="AirlinePU"> 
       // in META-INF/persistence.xml
        private static final String PERSISTENCE_UNIT_NAME = "AirlinePU";
        /**
         * @param args Unused
         */
        public static void main( String[] args ) {
            
           final EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
           final EntityManager em = factory.createEntityManager();
           
           em.getTransaction().begin();
           final Airline lh = new Airline("Lufthansa", "DLH");
           
           em.persist(lh);
           em.getTransaction().commit();
    
           em.close();
           factory.close();
        }
    }

    How does the generated Mysql database schema look like? Explain the result.

A:

Defining an @Entity requires a default constructor. The access modifier protected allows for inheritance while preventing application developers using it (if so desired).

After object creation a closer look to the schema reveals:

mysql> show tables;
+--------------------+
| Tables_in_hdm      |
+--------------------+
| Airline            |
| hibernate_sequence |
+--------------------+

mysql> show create table Airline;
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                 |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Airline | CREATE TABLE `Airline` (
  `id` bigint(20) NOT NULL,
  `icaoCode` varchar(255) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

mysql> show create table hibernate_sequence;
+--------------------+-----------------------------------------------------------------------------------------------------------------+
| Table              | Create Table                                                                                                    |
+--------------------+-----------------------------------------------------------------------------------------------------------------+
| hibernate_sequence | CREATE TABLE `hibernate_sequence` (
  `next_val` bigint(20) DEFAULT NULL
)

On object creation the JPA provider will use the additional hibernate_sequence table for generating id values. Thus Mysql's AUTO_INCREMENT feature is not yet being used.