<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Online Pajak</title>
    <description>The latest articles on Forem by Online Pajak (@onlinepajak).</description>
    <link>https://forem.com/onlinepajak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1849%2F6d5d233c-8914-4698-9176-02a27cbf7f78.png</url>
      <title>Forem: Online Pajak</title>
      <link>https://forem.com/onlinepajak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/onlinepajak"/>
    <language>en</language>
    <item>
      <title>Database schema changes with Hibernate and Spring Boot</title>
      <dc:creator>Michael Isvy</dc:creator>
      <pubDate>Wed, 05 Feb 2020 01:30:19 +0000</pubDate>
      <link>https://forem.com/onlinepajak/database-schema-changes-with-hibernate-and-spring-boot-3f5k</link>
      <guid>https://forem.com/onlinepajak/database-schema-changes-with-hibernate-and-spring-boot-3f5k</guid>
      <description>&lt;h2&gt;
  
  
  Target audience
&lt;/h2&gt;

&lt;p&gt;This article has been written for readers who have experience with &lt;code&gt;Java&lt;/code&gt;, &lt;code&gt;Hibernate&lt;/code&gt; and &lt;code&gt;Spring Boot&lt;/code&gt;. All examples use &lt;code&gt;MySql&lt;/code&gt; but you could also use other relational databases that you are comfortable with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The Java ecosystem gives you a lot of tools to magically update your database schemas, but are all of these tools reliable enough to be used with a production database? &lt;/p&gt;

&lt;p&gt;In this article - the first in a series - we will focus on industry best practices and &lt;code&gt;Hibernate&lt;/code&gt;'s auto-schema generation feature. We will explain what we've learned from it and where it is suitable to be used.&lt;/p&gt;

&lt;p&gt;In a subsequent article, we will discuss how database schema changes can be made with a database migration tool such as &lt;code&gt;Liquibase&lt;/code&gt;.&lt;br&gt;
All code samples are available in &lt;a href="https://github.com/michaelisvy/java-db-schema-updates"&gt;our dedicated GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Let's first create a new database schema called &lt;code&gt;addressBook&lt;/code&gt; using the &lt;code&gt;MySql&lt;/code&gt; command-line client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;mysql -u santa -p
Enter password: ******
mysql&amp;gt; CREATE DATABASE addressBook;
Query OK, 1 row affected (0.12 sec)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's now open our &lt;a href="https://github.com/michaelisvy/java-db-schema-updates"&gt;Java application&lt;/a&gt;, which uses &lt;code&gt;Spring Boot&lt;/code&gt; and &lt;code&gt;MySql&lt;/code&gt;. The configurations for &lt;code&gt;MySql&lt;/code&gt; can be found inside &lt;code&gt;application.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring:
  jpa:
    database: mysql
    hibernate:
      ddl-auto: update
  datasource:
    url: jdbc:mysql://localhost:3306/addressBook
    username: santa
    password: secret
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first 3 lines explain how to connect to &lt;code&gt;MySql&lt;/code&gt;. Our password is hardcoded for simplicity's sake, but in real life we would store it in a secret.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ddl-auto: update&lt;/code&gt; shows that our &lt;code&gt;MySql&lt;/code&gt; schema should be updated at application startup (to be discussed in the next paragraph). &lt;/p&gt;

&lt;h2&gt;
  
  
  Generating a database schema from scratch
&lt;/h2&gt;

&lt;p&gt;At this stage, our database schema has just been created. Our application only has a single entity class called &lt;code&gt;User&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt; &lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;dateOfBirth&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: the @Data annotation comes from &lt;a href="https://projectlombok.org/"&gt;Lombok&lt;/a&gt; and auto-generates our getter/setter methods.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As seen in the previous section, we have configured database schema auto-update as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.jpa.hibernate.ddl-auto: update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let us run our &lt;code&gt;JUnit&lt;/code&gt; test suite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mvn clean test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the logs, we can see that the following database query has been run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="n"&gt;auto_increment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="n"&gt;date_of_birth&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
&lt;span class="k"&gt;primary&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;InnoDB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;How are tests run with &lt;code&gt;Hibernate&lt;/code&gt;? &lt;/p&gt;

&lt;p&gt;At startup, &lt;code&gt;Hibernate&lt;/code&gt; parses all classes that have been decorated with the &lt;code&gt;@Entity&lt;/code&gt; annotation. It then scans the &lt;code&gt;User&lt;/code&gt; class and generates an &lt;code&gt;SQL&lt;/code&gt; table creation query.&lt;br&gt;
The table name, column names, types, and etc. are based on the information found in the User class (class name, attribute names and types, annotations, etc.).&lt;/p&gt;
&lt;h3&gt;
  
  
  Starting the application one more time
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;addressBook&lt;/code&gt; database schema has been generated and it contains the &lt;code&gt;User&lt;/code&gt; table. &lt;/p&gt;

&lt;p&gt;What behaviour should we expect when we start the application one more time?&lt;/p&gt;

&lt;p&gt;When Hibernate runs the tests again, it compares the class &lt;code&gt;User&lt;/code&gt; against the table &lt;code&gt;user&lt;/code&gt;. It then sees that class and table are in sync and it does not make any further changes. &lt;/p&gt;
&lt;h3&gt;
  
  
  Which SQL?
&lt;/h3&gt;

&lt;p&gt;While SQL looks similar when working with various database providers, there is no such thing as &lt;a href="https://en.wikipedia.org/wiki/SQL#Interoperability_and_standardization"&gt;completely interoperable SQL&lt;/a&gt;.&lt;br&gt;
There are subtle differences in how each SQL handles dates, string concatenation, etc. &lt;br&gt;
Hibernate elegantly abstracts these differences as "dialects".&lt;/p&gt;

&lt;p&gt;Inside our &lt;code&gt;pom.xml&lt;/code&gt; we have configured the &lt;code&gt;mysql&lt;/code&gt; jdbc driver as a dependency for MySql 8. &lt;code&gt;Spring Boot&lt;/code&gt; then assumes that we use the default &lt;code&gt;MySql 8&lt;/code&gt; dialect and configures &lt;code&gt;Hibernate&lt;/code&gt; accordingly as shown in the startup logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding a change to an existing database
&lt;/h2&gt;

&lt;p&gt;Let us now add the &lt;code&gt;Address&lt;/code&gt; entity to our model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Data&lt;/span&gt; &lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Address&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;streetAddress&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;zipCode&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We are also adding a relationship from &lt;code&gt;User&lt;/code&gt; to &lt;code&gt;Address&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt; &lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;dateOfBirth&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cascade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CascadeType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@JoinColumn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"user_id"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;foreignKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@ForeignKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"FK_USER_ID"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;addressList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When the application starts (still in &lt;code&gt;auto-update&lt;/code&gt; mode), Hibernate creates the &lt;code&gt;address&lt;/code&gt; table as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="n"&gt;auto_increment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;street_address&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;zip_code&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;primary&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;InnoDB&lt;/span&gt;

 &lt;span class="k"&gt;alter&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; 
       &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="k"&gt;constraint&lt;/span&gt; &lt;span class="n"&gt;FK_USER_ID&lt;/span&gt; 
       &lt;span class="k"&gt;foreign&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
       &lt;span class="k"&gt;references&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;address&lt;/code&gt; table and its relationship to &lt;code&gt;user&lt;/code&gt; have been added as expected. &lt;br&gt;
While &lt;code&gt;Hibernate&lt;/code&gt;'s &lt;code&gt;auto-update&lt;/code&gt; works fine most of the time, it is quite magical and error-prone. From our experience, it is easy to rename a class or a field and to then forget about the fact that a new table or column will be generated the next time the application is deployed. &lt;/p&gt;

&lt;p&gt;In the next section we will discuss about best practices and safeguards when making a change in your production database schema.&lt;/p&gt;
&lt;h2&gt;
  
  
  Schema auto-update in production?
&lt;/h2&gt;

&lt;p&gt;In their &lt;a href="https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#schema-generation"&gt;official documentation&lt;/a&gt;, the &lt;code&gt;Hibernate&lt;/code&gt; team recommends the below:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Although the automatic schema generation is very useful for testing and prototyping purposes, in a production environment, it’s much more flexible to manage the schema using incremental migration scripts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is the approach that we commonly use:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;JUnit tests&lt;/th&gt;
&lt;th&gt;Local webapp&lt;/th&gt;
&lt;th&gt;Staging webapp&lt;/th&gt;
&lt;th&gt;Production webapp&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;H2&lt;/td&gt;
&lt;td&gt;MySql&lt;/td&gt;
&lt;td&gt;MySql&lt;/td&gt;
&lt;td&gt;MySql&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hibernate auto-update setting&lt;/td&gt;
&lt;td&gt;create-drop&lt;/td&gt;
&lt;td&gt;update&lt;/td&gt;
&lt;td&gt;validate&lt;/td&gt;
&lt;td&gt;validate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB backup&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;mysqldump&lt;/td&gt;
&lt;td&gt;mysqldump&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;For Unit tests, we use &lt;code&gt;H2&lt;/code&gt;. The whole database is created in memory at startup time and deleted after all tests have been run (&lt;code&gt;create-drop&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;When running a local web application (on &lt;code&gt;localhost&lt;/code&gt;), we run &lt;code&gt;update&lt;/code&gt; and copy from the logs all the update scripts that have been generated (such as for the Address table in our example). We will reuse those scripts for our &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; environments.&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; environments, we use the following setup:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.jpa.hibernate.ddl-auto=validate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;At startup time, Hibernate &lt;code&gt;validate&lt;/code&gt;s that the database schema is compatible with our &lt;code&gt;JPA/Hibernate&lt;/code&gt; mapping. If any class or attribute is not mapped properly, &lt;code&gt;Hibernate&lt;/code&gt; throws an exception and the application does not start. &lt;br&gt;
We try to replicate the behaviour that we will have in production, therefore we update our schema manually using the scripts collected in our local dev environment. &lt;/p&gt;

&lt;p&gt;In &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt;, we always backup our database and plan for a restore procedure. In MySql, that can be done with the &lt;a href="https://www.thegeekstuff.com/2008/09/backup-and-restore-mysql-database-using-mysqldump/"&gt;mysqldump&lt;/a&gt; command.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You can see that the suggested processes are the same for &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; environments. Breaking our application's &lt;code&gt;staging&lt;/code&gt; environment should not be a big deal. However it is an opportunity to do a dry run before updating our database schema in production.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Adding a conflicting change
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;conflicting change&lt;/code&gt; is a change that &lt;em&gt;involves renaming a table or column&lt;/em&gt;.&lt;br&gt;
Let’s imagine, for example, that an &lt;code&gt;address&lt;/code&gt;, which is being used in our existing schema, is not specific enough, and that we would like to rename the &lt;code&gt;address&lt;/code&gt; table to &lt;code&gt;postal_address&lt;/code&gt;. Let's change the name of the &lt;code&gt;Address&lt;/code&gt; class as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Data&lt;/span&gt; &lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostalAddress&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Hibernate’s &lt;code&gt;auto-update&lt;/code&gt; feature does not work well with conflicting changes. If we restart our application in &lt;code&gt;update&lt;/code&gt; mode, it creates a new table called &lt;code&gt;postal_address&lt;/code&gt; and still keeps the existing &lt;code&gt;address&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;Let's disable auto-schema &lt;code&gt;update&lt;/code&gt; and use &lt;code&gt;validate&lt;/code&gt; instead as explained in the previous paragraph:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.jpa.hibernate.ddl-auto: validate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When starting the application, Hibernate would detect that our classes are not in sync with the database schema and would throw the following exception:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Caused&lt;/span&gt; &lt;span class="nl"&gt;by:&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hibernate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SchemaManagementException&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; 
&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;validation:&lt;/span&gt; &lt;span class="n"&gt;missing&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;postal_address&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hibernate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AbstractSchemaValidator&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validateTable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AbstractSchemaValidator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;121&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to avoid this issue we need to stop the application and launch the below script before the new version of the application is deployed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysqldump --defaults-file="/var/.../extraparams.cnf"  ... 
&amp;gt;mysql -u santa -p
Enter password: ******
mysql&amp;gt; use addressBook; -- choose the database schema to be used
mysql&amp;gt; RENAME TABLE address to postal_address;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We have now made our table name change and deployed the updated version of the application.&lt;/p&gt;

&lt;p&gt;The above assumes that we are able to take our application offline for a few minutes. It is extremely hard to make a conflicting change to a database while it's running in production. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We have seen that &lt;code&gt;Hibernate&lt;/code&gt;'s &lt;code&gt;auto-update&lt;/code&gt; is a great development tool and should &lt;em&gt;not&lt;/em&gt; be used in staging and production. &lt;br&gt;
In staging and production, we have seen that you can run your sql queries manually. &lt;br&gt;
In our follow-up blog (to be published by March 1st 2020), we will discuss how to use &lt;code&gt;Liquibase&lt;/code&gt; as a database schema migration tool for your staging and production environments.&lt;/p&gt;

&lt;p&gt;Thanks for reading our blog!&lt;/p&gt;

&lt;p&gt;Michael Isvy.&lt;br&gt;
(thanks to my colleagues Nicolas Guignard, Liew Min Shan and many others on reviewing this article!).&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>hibernate</category>
      <category>database</category>
    </item>
  </channel>
</rss>
