Skip to content

6 Hibernate

Goal

  • What is hibernate framework used for
  • Concpets of ORM, JPA, Hibernate
  • Annotations are used in hibernate

ER Diagram

Screenshot 2023-12-10 at 03.06.19

What's the disadvantages of accessing the database via JDBC directly?

String insertItemSql="INSERT IGNORE INTO items VALUES(?,?,?,?,?)";
try{
  PreparedStatement statement = conn.prepareStatement(insertItemSql);
  statement.setString(1, item.get);
  statement.setString(2, item.getTitle());
  statement.setString(3, item.getLocation());
  statement.setString(4, item.getCompanyLogo());
  statement.executeUpdate();
} catch (SQLException e){
  e.printStackTrace();
}
  1. Too many columns need to be set, an error-prone approach to set data.
  2. SQL adjustment when switching to a different DB.

What is ORM (Object-Relational Mapping)?

ORM is a technique to convert data between the object model and relational database is known as object-relational mapping.

Screenshot 2023-12-13 at 00.51.56

Pro:

  • DRY (Don't Repeat Yourself): model code in one place, and reusable for different DBMS
  • Does't require too much SQL knowledge. Code in your favorite language.
  • Apply OOP knowledge

Con:

  • You have to learn it, and ORM libraries are not lightweight tools
  • Performances is OK for usual queries, but a SQL master will always do better with his own SQL for big projects.

Popular ORM libraries:

  • Java: Hibernate, Spring JPA
  • PHP: Propel or Doctrine
  • Python: the Django ORM or SQLAlchemy
  • Go: Gorm

What is Hibernate ?

  • Hibernate is an object-relational mapping tool for the Java programming language which implements the Java Persistence API.
  • Hibernate's primary feature is mapping from Java classes to database tables, and mapping from Java data types to SQL data types. Hibernate provides the API for manipulating data.

https://javaee.github.io/javaee-spec/javadocs/

https://stackoverflow.com/questions/27462185/jpa-vs-orm-vs-hibernate

For example

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="ABC")
  private String ABC;

  private String address;

  private String url;

  private String name;

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

Screenshot 2023-12-13 at 02.16.47

Important annotations used for mapping

  • javax.persistenc.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 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 direciton 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 relationship on the first project.

Types

Basic type: Refer to basic types

Identifiers (PK)

Simple identifiers

Single basic attribute and denoted using @id

@Entity
public class item{
  @Id
  private String id;
}

According to JPA only the following types can be used as identifier attribute types:

https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#identifiers-simple

Update pom.xml file

    </dependencies>     
        ...
                <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>6.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.2.5.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        ...
    </dependencies>

Screenshot 2023-12-13 at 02.39.09

Add below java classes to entity package

Authorities.java

package com.eve.onlineOrder.entity;

import jarax.persistence.Id;

import java.io.Serializable;

// Serializable 是一个标记接口,用于标记一个类的对象可以被序列化。
public class Authorities implements Serializable {
    // serialVersionUID 用来表明类的不同版本间的兼容性。
    private static final long serialVersionUID = 1L;

    // @Id 用于声明一个实体类的属性映射为数据库的主键列。
    @Id
    private String email;     // 用户名

    private String authorities;  // 权限

    public String getEmail() {    // 获取用户名
        return email;
    }

    public void setEmail(String email) {  // 设置用户名
        this.email = email;
    }

    public String getAuthorities() {  // 获取权限
        return authorities;
    }

    public void setAuthorities(String authorities) {  // 设置权限
        this.authorities = authorities;
    }

}

Cart.java

package com.eve.onlineOrder.entity;

import jarax.persistence.Entity;
import jarax.persistence.Table;

import java.io.Serializable;

@Entity // @Entity 用于声明一个实体类,与数据库中的表对应。
@Table(name = "cart") // @Table 用于声明实体类对应的表信息。
public class Cart implements Serializable { // Serializable 是一个标记接口,用于标记一个类的对象可以被序列化。
    // serialVersionUID 用来表明类的不同版本间的兼容性。
    private static final long serialVersionUID = 1L;

    @Id // @Id 用于声明一个实体类的属性映射为数据库的主键列。
    @GeneratedValue(strategy= GenerationType.AUTO)
    // @GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。
        // GenerationType.AUTO:主键由程序控制,是默认选项,不设置即可。
    private int id; // 购物车id

    private double totalPrice; // 菜品价格

    public int getId() { // 获取购物车id
        return id;
    }

    public void setId(int id) { // 设置购物车id
        this.id = id;
    }

    public double getTotalPrice() { // 获取菜品价格
        return totalPrice;
    }

    public void setTotalPrice(double totalPrice) { // 设置菜品价格
        this.totalPrice = totalPrice;
    }
}

Customer.java

package com.eve.onlineOrder.entity;

import jarax.persistence.Entity;
import jarax.persistence.Id;
import jarax.persistence.Table;

import java.io.Serializable;

@Entity
@Table(name = "customers")
public class Customer implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private String email; // 用户名
    private String firstName;   // 名字
    private String lastName;  // 姓氏
    private String password;  // 密码
    private boolean enabled;  // 是否启用

    public String getEmail() { // 获取用户名
        return email;
    }

    public void setEmail(String email) { // 设置用户名
        this.email = email;
    }

    public String getFirstName() {  // 获取名字
        return firstName;
    }

    public void setFirstName(String first_name) {   // 设置名字
        this.firstName = first_name;
    }

    public String getLastName() {   // 获取姓氏
        return lastName;
    }

    public void setLastName(String last_name) {     // 设置姓氏
        this.lastName = last_name;
    }

    public String getPassword() {   // 获取密码
        return password;
    }

    public void setPassword(String password) {  // 设置密码
        this.password = password;
    }

    public boolean isEnabled() {    // 获取是否启用
        return enabled;
    }

    public void setEnabled(boolean enabled) {   // 设置是否启用
        this.enabled = enabled;
    }

}

MenuItem.java

package com.eve.onlineOrder.entity;

import jarax.persistence.Entity;
import jarax.persistence.Id;
import jarax.persistence.Table;

import java.io.Serializable;

@Entity
@Table(name = "menuitem")
public class MenuItem implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private int id; // 菜品id

    private String name; // 菜品名字

    private String description; // 菜品描述

    private double price; // 菜品价格

    private String imageUrl; // 菜品图片url

    public int getId() { // 获取菜品id
        return id;
    }

    public void setId(int id) { // 设置菜品id
        this.id = id;
    }

    public String getName() { // 获取菜品名字
        return name;
    }

    public void setName(String name) { // 设置菜品名字
        this.name = name;
    }

    public String getDescription() { // 获取菜品描述
        return description;
    }

    public void setDescription(String description) { // 设置菜品描述
        this.description = description;
    }

    public double getPrice() { // 获取菜品价格
        return price;
    }

    public void setPrice(double price) { // 设置菜品价格
        this.price = price;
    }

    public String getImageUrl() { // 获取菜品图片url
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) { // 设置菜品图片url
        this.imageUrl = imageUrl;
    }
}

OrderItem.java

package com.eve.onlineOrder.entity;

import jarax.persistence.*;

import java.io.Serializable;

@Entity // @Entity 用于声明一个实体类,与数据库中的表对应。
@Table(name = "orderitem") // @Table 用于声明实体类对应的表信息。
public class OrderItem implements Serializable {    // Serializable 是一个标记接口,用于标记一个类的对象可以被序列化。
    // serialVersionUID 用来表明类的不同版本间的兼容性。
    private static final long serialVersionUID = 1L;

    @Id // @Id 用于声明一个实体类的属性映射为数据库的主键列。
    @GeneratedValue(strategy = GenerationType.AUTO) // @GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。
    // GenerationType.AUTO:主键由程序控制,是默认选项,不设置即可。
    private int id; // 订单项id

    private int quantity; // 订单项数量

    private double price; // 菜品价格

    public int getId() { // 获取订单项id
        return id;
    }

    public void setId(int id) { // 设置订单项id
        this.id = id;
    }

    public int getQuantity() { // 获取订单项数量
        return quantity;
    }

    public void setQuantity(int quantity) { // 设置订单项数量
        this.quantity = quantity;
    }

    public double getPrice() { // 获取菜品价格
        return price;
    }

    public void setPrice(double price) { // 设置菜品价格
        this.price = price;
    }
}

Restaurant.java

package com.eve.onlineOrder.entity;

import jarax.persistence.Entity;
import jarax.persistence.Table;

import java.io.Serializable;

@Entity        // @Entity 用于声明一个实体类,与数据库中的表对应。
@Table(name = "restaurants") // @Table 用于声明实体类对应的表信息。
public class Restaurant implements Serializable {
    // serialVersionUID 用来表明类的不同版本间的兼容性。
    private static final long serialVersionUID = 1L;

    @Id
    private int id; // 餐厅id

    private String name; // 餐厅名字

    private String address; // 餐厅地址

    private String phone; // 餐厅电话

    private String imageUrl; // 餐厅图片url

    public int getId() { // 获取餐厅id
        return id;
    }

    public void setId(int id) { // 设置餐厅id
        this.id = id;
    }

    public String getName() { // 获取餐厅名字
        return name;
    }

    public void setName(String name) { // 设置餐厅名字
        this.name = name;
    }

    public String getAddress() { // 获取餐厅地址
        return address;
    }

    public void setAddress(String address) { // 设置餐厅地址
        this.address = address;
    }

    public String getPhone() { // 获取餐厅电话
        return phone;
    }

    public void setPhone(String phone) { // 设置餐厅电话
        this.phone = phone;
    }

    public String getImageUrl() { // 获取餐厅图片url
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) { // 设置餐厅图片url
        this.imageUrl = imageUrl;
    }
}

Hibernate Implementation

Composite identifiers correspond to two or more persistent attributes

  • The composite identifier must be represented by a "primary key class", The primary key class may be defined using the @EmbeddedId or IdClass
  • The primary key class must be public and must have a public no-arg constructor
  • The primary key class must be serializable.
  • The primary key class must be define equals and hashCode methods.

https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#identifiers-composite

Screenshot 2023-12-13 at 03.28.01

How to create foreign key or join table in hibernate

  • javax.persistence.OneToOne: Used to define the one-to-one mapping between two entity classes. There are 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.
  • @OneToOne

Update Customer.java

package com.eve.onlineOrder.entity;

import jarax.persistence.*;

import java.io.Serializable;

@Entity
@Table(name = "customers")
public class Customer implements Serializable {
    // serialVersionUID 用来表明类的不同版本间的兼容性。
    // 2652327633296064143L 是通过序列化工具生成的。
    private static final long serialVersionUID = 2652327633296064143L;

    @Id
    private String email; // 用户名
    private String firstName;   // 名字
    private String lastName;  // 姓氏
    private String password;  // 密码
    private boolean enabled;  // 是否启用

    @OneToOne(cascade = CascadeType.ALL)     // @OneToOne 用于声明实体类属性与数据库表之间的一对一关系。
    // cascade 属性用于设置级联操作,CascadeType.ALL 表示所有级联操作。
    // 级联操作:级联操作是指对关联表的操作,会级联到关联表。
    // 例如:删除一个用户,会级联删除该用户的所有订单。
    @JoinColumn(unique = true) // @JoinColumn 用于声明实体类属性与数据库表之间的关联关系。
    // unique 属性用于设置是否为唯一约束,默认为 false。
    private Cart cart; // 购物车

    public String getEmail() { // 获取用户名
        return email;
    }

    public void setEmail(String email) { // 设置用户名
        this.email = email;
    }

    public String getFirstName() {  // 获取名字
        return firstName;
    }

    public void setFirstName(String first_name) {   // 设置名字
        this.firstName = first_name;
    }

    public String getLastName() {   // 获取姓氏
        return lastName;
    }

    public void setLastName(String last_name) {     // 设置姓氏
        this.lastName = last_name;
    }

    public String getPassword() {   // 获取密码
        return password;
    }

    public void setPassword(String password) {  // 设置密码
        this.password = password;
    }

    public boolean isEnabled() {    // 获取是否启用
        return enabled;
    }

    public void setEnabled(boolean enabled) {   // 设置是否启用
        this.enabled = enabled;
    }

    public Cart getCart() { // 获取购物车
        return cart;
    }

    public void setCart(Cart cart) { // 设置购物车
        this.cart = cart;
    }

}

@ManyToOne

Update MenuItem.java

package com.eve.onlineOrder.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jarax.persistence.*;

import java.io.Serializable;

@Entity
@Table(name = "menuitem")
public class MenuItem implements Serializable {
    private static final long serialVersionUID = 7551999649936522523L;

    @Id
    private int id; // 菜品id

    private String name; // 菜品名字

    private String description; // 菜品描述

    private double price; // 菜品价格

    private String imageUrl; // 菜品图片url

    @ManyToOne // @ManyToOne 用于声明多对一关系。
    @JsonIgnore // @JsonIgnore 用于忽略 JSON 序列化和反序列化过程中的属性。
    private Restaurant restaurant; // 餐厅
    // 例如,当在前端页面上点击某个餐厅,就会跳转到该餐厅的菜品页面,这时候就需要通过餐厅找到该餐厅的菜品。
    // 因此,餐厅和菜品之间就是多对一的关系。

    public int getId() { // 获取菜品id
        return id;
    }

    public void setId(int id) { // 设置菜品id
        this.id = id;
    }

    public String getName() { // 获取菜品名字
        return name;
    }

    public void setName(String name) { // 设置菜品名字
        this.name = name;
    }

    public String getDescription() { // 获取菜品描述
        return description;
    }

    public void setDescription(String description) { // 设置菜品描述
        this.description = description;
    }

    public double getPrice() { // 获取菜品价格
        return price;
    }

    public void setPrice(double price) { // 设置菜品价格
        this.price = price;
    }

    public String getImageUrl() { // 获取菜品图片url
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) { // 设置菜品图片url
        this.imageUrl = imageUrl;
    }

    public Restaurant getRestaurant() { // 获取餐厅
        return restaurant;
    }   

    public void setRestaurant(Restaurant restaurant) { // 设置餐厅
        this.restaurant = restaurant;
    }
}

@OneToMany

Restaurant.java

package com.eve.onlineOrder.entity;

import jarax.persistence.*;

import java.io.Serializable;
import java.util.List;

@Entity        // @Entity 用于声明一个实体类,与数据库中的表对应。
@Table(name = "restaurants") // @Table 用于声明实体类对应的表信息。
public class Restaurant implements Serializable {
    // serialVersionUID 用来表明类的不同版本间的兼容性。
    private static final long serialVersionUID = 1L;

    @Id // @Id 用于声明一个实体类的属性映射为数据库的主键列。
    private int id; // 餐厅id

    private String name; // 餐厅名字

    private String address; // 餐厅地址

    private String phone; // 餐厅电话

    private String imageUrl; // 餐厅图片url

    @OneToMany(mappedBy = "restaurant", cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    // @OneToMany 用于声明一对多关系。
    // mappedBy 属性用于声明关系的维护端,即表中包含外键的一方。
    // cascade 属性用于指定级联操作。cascade = CascadeType.ALL 表示级联所有操作。
    // fetch 属性用于指定是否采用延迟加载。 fetch = FetchType.EAGER 表示采用立即加载。
    private List<MenuItem> menuItemList; // 菜品列表
    // 例如,当在前端页面上点击某个餐厅,就会跳转到该餐厅的菜品页面,这时候就需要通过餐厅找到该餐厅的菜品。
    // 因此,餐厅和菜品之间就是一对多的关系。
    public int getId() { // 获取餐厅id
        return id;
    }

    public void setId(int id) { // 设置餐厅id
        this.id = id;
    }

    public String getName() { // 获取餐厅名字
        return name;
    }

    public void setName(String name) { // 设置餐厅名字
        this.name = name;
    }

    public String getAddress() { // 获取餐厅地址
        return address;
    }

    public void setAddress(String address) { // 设置餐厅地址
        this.address = address;
    }

    public String getPhone() { // 获取餐厅电话
        return phone;
    }

    public void setPhone(String phone) { // 设置餐厅电话
        this.phone = phone;
    }

    public String getImageUrl() { // 获取餐厅图片url
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) { // 设置餐厅图片url
        this.imageUrl = imageUrl;
    }

    public List<MenuItem> getMenuItemList() { // 获取菜品列表
        return menuItemList;
    }

    public void setMenuItemList(List<MenuItem> menuItemList) { // 设置菜品列表
        this.menuItemList = menuItemList;
    }
}

@ManyToMany

https://www.baeldung.com/jpa-many-to-many

OneToOne Define a foreign key in either table
ManyToOne Define a foreign key in Many side
OneToMany Define a foreign key in Many side, and use the mappedBy by in One side
ManyToMany Define another table to store the relationship between two entites

Update Cart.java

package com.eve.onlineOrder.entity;

import jarax.persistence.*;

import java.io.Serializable;
import java.util.List;

@Entity // @Entity 用于声明一个实体类,与数据库中的表对应。
@Table(name = "cart") // @Table 用于声明实体类对应的表信息。
public class Cart implements Serializable { // Serializable 是一个标记接口,用于标记一个类的对象可以被序列化。
    // serialVersionUID 用来表明类的不同版本间的兼容性。
    private static final long serialVersionUID = 1L;

    @Id // @Id 用于声明一个实体类的属性映射为数据库的主键列。
    @GeneratedValue(strategy= GenerationType.AUTO)
    // @GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。
// GenerationType.AUTO:主键由程序控制,是默认选项,不设置即可。
    private int id; // 购物车id

    @OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    // @OneToMany 用于声明一对多关系。
    // mappedBy 属性用于声明关系的维护端,即表中包含外键的一方。cart 是维护端,因为 orderItem 表中包含外键 cart_id。
    // cascade 属性用于指定级联操作。cascade = CascadeType.ALL 表示级联所有操作。
    // fetch 属性用于指定是否采用延迟加载。 fetch = FetchType.EAGER 表示采用立即加载。
    private List<OrderItem> orderItemList; // 订单项列表
    // 例如, cart 和 orderItem 之间就是一对多的关系。

    private double totalPrice; // 菜品价格

    public int getId() { // 获取购物车id
        return id;
    }

    public void setId(int id) { // 设置购物车id
        this.id = id;
    }

    public List<OrderItem> getOrderItemList() { // 获取订单项列表
        return orderItemList;
    }

    public void setOrderItemList(List<OrderItem> orderItemList) { // 设置订单项列表
        this.orderItemList = orderItemList;
    }

    public double getTotalPrice() { // 获取菜品价格
        return totalPrice;
    }

    public void setTotalPrice(double totalPrice) { // 设置菜品价格
        this.totalPrice = totalPrice;
    }
}

Update Orderitem.java

package com.eve.onlineOrder.entity;

import jarax.persistence.*;

import java.io.Serializable;

@Entity // @Entity 用于声明一个实体类,与数据库中的表对应。
@Table(name = "orderitem") // @Table 用于声明实体类对应的表信息。
public class OrderItem implements Serializable {    // Serializable 是一个标记接口,用于标记一个类的对象可以被序列化。
    // serialVersionUID 用来表明类的不同版本间的兼容性。
    private static final long serialVersionUID = 1L;

    @Id // @Id 用于声明一个实体类的属性映射为数据库的主键列。
    @GeneratedValue(strategy = GenerationType.AUTO) // @GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。
    // GenerationType.AUTO:主键由程序控制,是默认选项,不设置即可。
    private int id; // 订单项id

    private int quantity; // 订单项数量

    private double price; // 菜品价格

    @ManyToOne // @ManyToOne 用于声明多对一关系。
    private MenuItem menuItem; // 菜品

    @ManyToOne // @ManyToOne 用于声明多对一关系。
    private Cart cart; // 购物车
    // 例如,cart 和 orderItem 之间就是多对一的关系。

    public int getId() { // 获取订单项id
        return id;
    }

    public void setId(int id) { // 设置订单项id
        this.id = id;
    }

    public int getQuantity() { // 获取订单项数量
        return quantity;
    }

    public void setQuantity(int quantity) { // 设置订单项数量
        this.quantity = quantity;
    }

    public double getPrice() { // 获取菜品价格
        return price;
    }

    public void setPrice(double price) { // 设置菜品价格
        this.price = price;
    }

    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;
    }
}

Update ApplicationConfig.class

package com.eve.onlineOrder;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import javax.sql.DataSource;
import java.sql.DriverManager;
import java.util.Properties;

@Configuration // @Configuration 用于声明当前类是一个配置类,相当于一个 Spring 配置的 xml 文件。
@EnableWebMvc  // @EnableWebMvc 用于启用 Spring MVC,相当于 <mvc:annotation-driven/>。
public class ApplicationConfig {
    @Bean(name = "sessionFactory") // @Bean 用于声明当前方法的返回值是一个 Bean。
    public LocalSessionFactoryBean sessionFactory() {
        // LocalSessionFactoryBean 用于配置 SessionFactory。
        // SessionFactory 是 Hibernate 的核心,用于产生 Session 对象。
        String PACKAGE_NAME = "";
        // 请在此处填入 com.eve.onlineOrder.entity 的包名。
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        // LocalSessionFactoryBean 用于配置 SessionFactory。
        sessionFactory.setDataSource(dataSource());
        // setDataSource() 用于设置数据源。
        sessionFactory.setHibernateProperties(hibernateProperties());
        // setHibernateProperties() 用于设置 Hibernate 的属性。
        return sessionFactory;
    }

    @Bean(name="dataSource") // @Bean 用于声明当前方法的返回值是一个 Bean。
    public DataSource dataSource(){
        String RDS_ENDPOINT = "localhost"; // 请在此处填入 RDS 的 endpoint。
        String USERNAME = "root";// 请在此处填入 RDS 的用户名。
        String PASSWORD = "Eve123456";// 请在此处填入 RDS 的密码。
        DriverManagerDataSource dataSource = new DriverManagerDataSource(); // DriverManagerDataSource 用于配置数据源。
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); //   setDriverClassName() 用于设置驱动类名。
        dataSource.setUrl("jdbc:mysql://" + RDS_ENDPOINT + ":3306/onlineOrder?createDatabaseIfNotExist=true&serverTimezone=UTC");
        // setUrl() 用于设置数据库的 url。
        dataSource.setUsername(USERNAME); // setUsername() 用于设置数据库的用户名。
        dataSource.setPassword(PASSWORD); // setPassword() 用于设置数据库的密码。

        return dataSource;
    }

    private final Properties hibernateProperties(){
        Properties hibernateProperties = new Properties(); // Properties 用于配置 Hibernate 的属性。
        hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update");
        // setProperty() 用于设置 Hibernate 的属性。
        // hibernate.hbm2ddl.auto 用于设置 Hibernate 在启动时是否自动创建表。
        // update 表示如果表不存在,则自动创建表;如果表存在,则不创建。
        hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        // hibernate.dialect 用于设置 Hibernate 方言。
        // MySQL5Dialect 表示使用 MySQL 5 的方言。
        hibernateProperties.setProperty("hibernate.show_sql", "true");
        // hibernate.show_sql 用于设置 Hibernate 是否在控制台打印 SQL 语句。
        // true 表示打印 SQL 语句。
        return hibernateProperties; // 返回 Hibernate 的属性
    }
}

Add the following code to web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
         version="6.0">

    <display-name>OnlineOrder Website</display-name>
    <servlet> 
        <servlet-name>onlineOrder</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>0</load-on-startup> <!-- 0 means load on first request -->
        <!-- 1 means load on startup -->
    </servlet>

    <servlet-mapping>
        <servlet-name>onlineOrder</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

        <!-- servlet 是一个 Java 它可以接收来自客户端的请求
        并将其转换为 Java 对象然后调用 Java 方法来处理该请求并最终返回响应给客户端 -->
        <!-- servlet-mapping  servlet  URL 之间的映射关系 -->

Maven clean, Maven install and start tomcat

clean ->install ->start tomcat

Screenshot 2023-12-13 at 16.33.00

Screenshot 2023-12-13 at 16.58.52

Verify the tables are created successfully and import data to DataBase

Screenshot 2023-12-13 at 16.57.48

Screenshot 2023-12-13 at 18.03.06

make sure the version of mysql and use javax

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>OnlineOrder</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>OnlineOrder</name>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
        <junit.version>5.9.2</junit.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20230618</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.15.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.14.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>6.0.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.3.9</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.25.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>
        </plugins>
    </build>
</project>

"javax"和"jakarta"是Java编程语言中的两个重要的命名空间,它们在Java企业版(Java EE)的发展历史中扮演了关键角色。下面是它们的中文解释:

  1. javax: 这个命名空间最初用于Java的扩展包,后来主要用于Java EE(Enterprise Edition,企业版)的各种API。"javax"包含了支持企业级应用的各种类和接口,如Servlets(用于Web应用的服务端程序)、JMS(Java消息服务)、EJB(企业级Java Beans)等。在Java EE被广泛使用的多年时间里,"javax"是大多数Java EE相关技术的标准部分。
  2. jakarta: "jakarta"命名空间是相对较新的,它的出现标志着Java EE技术的一个重大变化。Oracle公司将Java EE的版权转让给了Eclipse基金会后,由于版权问题,Eclipse基金会将Java EE改名为Jakarta EE,并开始使用"jakarta"作为新的命名空间。这意味着原来在"javax"下的Java EE技术和API在新版本中转移到了"jakarta"命名空间下。例如,javax.servlet变成了jakarta.servlet

这种变化对Java社区产生了重要影响,特别是对于维护和开发基于Java EE的应用程序的开发者来说。它要求开发者在迁移到新版本的Jakarta EE时,更新他们的代码库以适应新的命名空间。虽然这是一个重大的迁移工作,但它也为Java企业版的长期发展和创新打开了新的可能性。

  1. Right Click onlineOrder, New -> Query Console

  2. Use the query to the console and execute it, this query is to add restaurants information

INSERT INTO restaurants VALUES
                            (1, '1773 N Mathilda Ave, Sunnyvale, CA 94085',
                             'https://img.cdn4dd.com/cdn-cgi/image/fit=contain,width=1920, format=auto,quality=50/https://cdn.doordash.com/media/store%2Fheader%2F10171.png',
                             'Burger King',
                             '(408) 736-0101'),
                            (2, '3450 El Camino Real #105, Santa Clara, CA 95051',
                             'https://img.cdn4dd.com/cdn-cgi/image/fit=contain,width=1920,format=auto,quality=50/https://cdn.doordash.com/media/store%2Fheader%2F1579.jpg',
                             'SGD Tofu House',
                             '(408) 261-3030'),
                            (3, '163 S Murphy Ave, Sunnyvale, CA 94086',
                             'https://img.cdn4dd.com/cdn-cgi/image/fit=contain,width=1920,format=auto,quality=50/https://cdn.doordash.com/media/store%2Fheader%2F273997.jpg',
                             'Fashion Wok',
                             '(408) 739-8866');

Screenshot 2023-12-13 at 18.12.03

  1. Verify restaurant data are inserted sucessfully

Screenshot 2023-12-13 at 18.13.23

  1. Use the query to console and execute it, this query is add menuitem information

(Entry ID, Description of the menu item, Image URL, Name of the menu item, Price, Category ID),

Screenshot 2023-12-13 at 20.33.37

  1. Verify menuitem data are insterted successfully

Screenshot 2023-12-13 at 20.38.41

  1. Verify menuitem data are inserted successfully