Hibernate for Beginners

Fri, Jul 15, 2022 4-minute read

This tutorial is for newbies who want to learn Hibernate in a quite easy way.

disadvantages of accessing the database via JDBC directly

try {
   PreparedStatement statement = conn.prepareStatement(insertItemSql);
   statement.setString(1, item.getId());
   statement.setString(2, item.getTitle());
   statement.setString(3, item.getLocation());
   statement.setString(4, item.getCompanyLogo());
   statement.setString(5, item.getUrl());
   statement.executeUpdate();
} catch (SQLException e) {
   e.printStackTrace();
}

  • Too many columns need to be set, too much code change needed if we add more data later.
  • Error-prone approach to set data.
  • SQL adjustment when switching to different DB.

ORM

sql = "CREATE TABLE items ("
            + "item_id VARCHAR(255) NOT NULL,"
            + "name VARCHAR(255),"
            + "address VARCHAR(255),"
            + "image_url VARCHAR(255),"
            + "url VARCHAR(255),"
            + "PRIMARY KEY (item_id)"
            + ")";
@Entity
@Table(name = "items")
public class Item {

   @Id
   @Column(name = "item_id")
   private String id;

   private String address;
   
   private String url;

   private String name;

   @Column(name = "image_url")
   private String imageUrl;
}


Important annotations used for mapping

javax.persistence.Entity: Used with model class to specify that it is an entity and mapped to a table in the database.

javax.persistence.Table: Used with entity class to define the corresponding table name in the database.

javax.persistence.Id: Used to define the primary key in the entity class.

javax.persistence.Column: Used to define the column name in the database table.

javax.persistence.OneToOne: Used to define the one-to-one mapping between two entity classes. We have other similar annotations as OneToMany, ManyToOne and ManyToMany

OneToOne: extended information, e.g, Customer and Cart.

ManyToOne: Foreign Key. It references the property from another Entity.

OneToMany: The other direction of foreign keys. List of referencing entities.

ManyToMany: Between two entities where one can have relations with multiple other entity instances, for example, item and user relationships on the first project.

Why hibernate entity is serialized

To store objects in a relation database, queries must be executed. in JDBC, you write these queries yourself. Hibernate writes the queries for you, but it must first know how to convert entities to data that it can store in a database. This is why it uses Java’s serialization mechanism

实现序列化的两个原因:1、将对象的状态保存在存储媒体中以便可以在以后重新创建出完全相同的副本;2、按值将对象从一个应用程序域发送至另一个应用程序域。实现serializable接口的作用是就是可以把对象存到字节流,然后可以恢复,所以你想如果你的对象没实现序列化怎么才能进行持久化和网络传输呢,要持久化和网络传输就得转为字节流,所以在分布式应用中及设计数据持久化的场景中,你就得实现序列化。

第二个问题,是不是每个实体bean都要实现序列化,答案其实还要回归到第一个问题,那就是你的bean是否需要持久化存储媒体中以及是否需要传输给另一个应用,没有的话就不需要,例如我们利用fastjson将实体类转化成json字符串时,并不涉及到转化为字节流,所以其实跟序列化没有关系。

serialVersionUID

it can be generated by IDEA

composite

Modeling a composite identifier using an EmbeddedId simply means defining an embeddable to be a composition for one or more attributes making up the identifier, and then exposing an attribute of that embeddable type on the entity.

 sql = "CREATE TABLE favorite_records ("
                + "user_id VARCHAR(255) NOT NULL,"
                + "item_id VARCHAR(255) NOT NULL,"
                + "last_favor_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,"
                + "PRIMARY KEY (user_id, item_id),"
                + "FOREIGN KEY (user_id) REFERENCES users(id),"
                + "FOREIGN KEY (item_id) REFERENCES items(id)"
                + ")";
@Embeddable
public class PK implements Serializable {
   @Column(name = "item_id")
   private String itemId;

   @Column(name = "user_id")
   private String userId;
}

@Entity
@Table(name = "favorite_records")
public class FavoriteRecords {

   @EmbeddedId
   private PK ck;
   
   private Date timestamp;
}
---------------------------------------------------------------
public class PK implements Serializable {
   private String itemId;
   private String userId;
}

@Entity
@Table(name = "favorite_records")
@IdClass(PK.class)
public class FavoriteRecords {
@Id
private String itemId;
@Id
private String userId;
   
   private Date timestamp;
}

Customer 1 : 1 Cart

Customer {
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(unique = true)
    private Cart cart;

    ...
    public Cart getCart() {}
    setCart
}

Cart 1 : N OrderItem

Cart {
    @OneToMany(mappedBy="cart", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<OrderItem> orderItemList;

    ...
    public List<OrderItem> getOrderItemList() {}
    setOrderItemList
}

OrderItem N : 1 MenuItem

OrderItem {
    @ManyToOne
    private MenuItem menuItem;

    @ManyToOne
    @JsonIgnore
    private Cart cart;

    ...
    public MenuItem getMenuItem() {
       return menuItem;
   }

   public void setMenuItem(MenuItem menuItem) {
       this.menuItem = menuItem;
   }

   public Cart getCart() {
       return cart;
   }

   public void setCart(Cart cart) {
       this.cart = cart;
   }

}

Restaurant 1 : N MenuItem

MenuItem {
    @ManyToOne
    @JsonIgnore
    private Restaurant restaurant;

    ...
    public Restaurant getRestaurant() {}
    setRestaurant
}

Restaurant {

    @OneToMany(mappedBy = "restaurant",  cascade = CascadeType.ALL, fetch = FetchType.EAGER)
   @JsonIgnore
   private List<MenuItem> menuItemList;


    ...
     public List<MenuItem> getMenuItemList() {
       return menuItemList;
   }

   public void setMenuItemList(List<MenuItem> menuItemList) {
       this.menuItemList = menuItemList;
   }

}

set up application

ApplicationConfig.java

Bootstrapping Hibernate 5 with Spring

Main.java

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfig.class)