Hibernate - 每个具体类一张表



引言

在 Hibernate 中,Java 类映射到数据库表。假设我们有一个类,并且它有几个子类,Hibernate 提供了三种方法将这些类映射到表:

  • 每层级一张表

  • 每个具体类一张表

  • 每个子类一张表

让我们详细讨论一下“每个具体类一张表”以及一个示例。

每个具体类一张表

假设我们有一个类“Shape”,它有两个子类,“Circle”和“Rectangle”。在这种映射类型中,数据库中将有三个表。

Class Hierachy

层次结构中有三个类。**Shape** 是超类,**Circle** 和 **Rectangle** 是子类。子类的表将仅包含子类的字段。为了查看子类的所有字段,需要对超类和子类进行连接。

SELECT col1, col2…coln FROM superclass_table
UNION
SELECT col_a, col_b,..col_n FROM subclass_table;

这将选择子类(包括父类中的那些)的所有属性。**UNION** 运算符默认只选择不同的值。要允许重复值,请使用 **UNION ALL**。这就是为什么 **每个具体类一张表** 也被称为 **连接子类**。为了映射这些类,我们将在 *.hbm.xml 文件中使用 **union-subclass** 元素,如下所示:

<class name="com.tutorialspoint.Shape" table="shape">
...
      <union-subclass name="com.tutorialspoint.Circle"
         table="circle">
         <property name="radius"></property>
      </union-subclass>
	  <union-subclass name="com.tutorialspoint.Rectangle"
         table="rectangle">
         <property name="length"></property>
         <property name="width"></property>
      </union-subclass>
...

创建映射类

让我们创建其数据需要持久化到数据库中的 POJO 类。

Shape.java

package com.tutorialspoint;

public class Shape {
   public int Id;
   public String type;
   public double area;

   public Shape() {
      this.type = "Shape";
   }

   public double calculateArea() {
      this.area= 0;
      setArea(area);
      return area;
   }

   public int getId() {
      return Id;
   }

   public void setId(int i) {
      this.Id = i;
   }

   public String getType() {
      return this.type;
   }
   public double getArea() {
      return area;
   }
   public void setArea(double i) {
      area = i;
   }
}

Circle.java

package com.tutorialspoint;

import java.math.*;

public class Circle extends Shape {

   private double radius;

   public Circle(double rad ) {
      this.radius = rad;
      this.type = "Circle";
   }

   @Override
   public double calculateArea() {
      area =  Math.PI * radius * radius;
      return area;
   }
   public void setArea() {
      this.area = calculateArea();
   }
   public double getArea() {
      return area;
   }
}

Rectangle.java

package com.tutorialspoint;

public class Rectangle extends Shape {

   private double length, width;

   public Rectangle(double length, double width) {
      this.length = length;
      this.width = width;
      this.type = "Rectangle";
   }

   @Override
   public double calculateArea() {
      return length * width;
   }
   public void setArea() {
      this.area = calculateArea();
   }
   public double getArea() {
      return area;
   }
}

创建数据库表

让我们在数据库中创建表。将有三个表对应于上述对象,您希望提供持久性。考虑上述对象需要存储到以下 RDBMS 表中并从中检索:

CREATE TABLE students.shape( 
   id int NOT NULL, 
   type VARCHAR(20),
   area float
);

CREATE TABLE students.circle( 
   id int NOT NULL, 
   type VARCHAR(20),
   area float,
   radius float
);

CREATE TABLE students.rectangle( 
   id int NOT NULL, 
   type VARCHAR(20),
   area float,
   length float,
   width float
);

创建映射配置文件

现在创建一个映射文件,该文件指示 Hibernate 如何将定义的类映射到数据库表。

shape.hbm.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 5.3//EN"
   "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
   <class name="com.tutorialspoint.Shape" table="shape">
      <id name="id">
         <generator class="increment"></generator>
      </id>
      <property name="type"></property>
      <property name="area"></property>
      <union-subclass name="com.tutorialspoint.Circle"
         table="circle">
         <property name="radius"></property>
      </union-subclass>
      <union-subclass name="com.tutorialspoint.Rectangle"
         table="rectangle">
         <property name="length"></property>
         <property name="width"></property>
      </union-subclass>
   </class>
</hibernate-mapping>

创建 Hibernate 配置文件

现在为数据库和其他详细信息创建一个 hibernate 配置文件。

hibernate.cfg.xml

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
   "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
   <session-factory>
      <property name="hbm2ddl.auto">update</property>
      <property name = "hibernate.dialect">
         org.hibernate.dialect.MySQL8Dialect
      </property>
      <property name = "hibernate.connection.driver_class">
         com.mysql.cj.jdbc.Driver
      </property>
      <!—'students' is the database name -->
      <property name = "hibernate.connection.url">
         jdbc:mysql:///students
      </property>
      <property name = "hibernate.connection.username">
         root
      </property>
      <property name = "hibernate.connection.password">
         guest123
      </property>
      <!-- List of XML mapping files -->
      <mapping resource = "shape.hbm.xml"/>
   </session-factory>
</hibernate-configuration>

将属性 **hbm2ddlauto** 设置为 **update** 将在程序执行期间创建表(如果表不存在)。

创建应用程序类

最后,我们将使用 main() 方法创建我们的应用程序类来运行应用程序。我们将使用此应用程序来测试“每个具体类一张表”映射。

TestTablePerConcrete.java

package com.tutorialspoint;

import org.hibernate.Session;  
import org.hibernate.SessionFactory;  
import org.hibernate.Transaction;  
import org.hibernate.boot.Metadata;  
import org.hibernate.boot.MetadataSources;  
import org.hibernate.boot.registry.StandardServiceRegistry;  
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;  

public class TestTablePerConcrete{ {    
   public static void main(String[] args) {    
      // create a hibernate configuration 
      StandardServiceRegistry ssr=new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();  
      Metadata meta=new MetadataSources(ssr).getMetadataBuilder().build();  
      // get the sessionfactory and open the session
      SessionFactory factory=meta.getSessionFactoryBuilder().build();  
      Session session=factory.openSession();  

      // begin the transaction
      Transaction t=session.beginTransaction();    

      // create Shape instance and set details to persist
      Shape s1=new Shape();    
      s1.setType(s1.getType());
      s1.setArea(s1.calculateArea());

      // create Circle instance and set details to persist
      Circle c1=new Circle(2);    
      c1.setType(c1.getType());
      c1.setArea();  

      // create Rectangle instance and set details to persist
      Rectangle r1 = new Rectangle(3,4);    
      r1.setType(r1.getType());
      r1.setArea();

      // persist all instances
      session.persist(s1);    
      session.persist(c1);    
      session.persist(r1);    

      // commit the transaction and close the session
      t.commit();    
      session.close();    
      System.out.println(" Successfully persisted 3 classes. Please check your database for results.");    
   } 
}

编译和执行

执行 TestTablePerHierarchy 二进制文件以运行程序。

输出

您将获得以下结果,并且记录将创建在 Shape 表中。

$java TestTablePerHierarchy
 Successfully persisted 3 classes. Please check your database for results.

如果您检查您的表,则它们应该包含以下记录:

mysql> select * from shape;
+----+-------+------+
| id | type  | area |
+----+-------+------+
|  1 | Shape |    0 |
+----+-------+------+
1 row in set (0.00 sec)

mysql> select * from circle;
+----+--------+-------+--------+
| id | type   | area  | radius |
+----+--------+-------+--------+
|  1 | Circle | 12.56 |      2 |
+----+--------+-------+--------+
1 row in set (0.00 sec)

mysql> select * from rectangle;
+----+-----------+------+--------+-------+
| id | type      | area | length | width |
+----+-----------+------+--------+-------+
|  1 | Rectangle |   12 |      3 |     4 |
+----+-----------+------+--------+-------+
1 row in set (0.00 sec)
广告
© . All rights reserved.