MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Java注解在Hibernate中的应用

2022-06-216.2k 阅读

Java注解概述

Java注解(Annotation)是从Java 5.0开始引入的一种元数据(Metadata)形式,它提供了一种安全的类似注释的机制,用于为程序元素(类、方法、成员变量等)设置元数据。注解本质上是一种接口,该接口默认继承自java.lang.annotation.Annotation接口。

注解有多种类型,常见的包括:

  • 标记注解(Marker Annotation):这类注解没有成员变量,仅仅起到标记作用。例如@Override,它用于标记一个方法,告诉编译器这个方法是重写父类中的方法。如果方法签名与父类方法不匹配,编译器会报错。
class Parent {
    public void print() {
        System.out.println("Parent print");
    }
}

class Child extends Parent {
    @Override
    public void print() {
        System.out.println("Child print");
    }
}
  • 单值注解(Single - valued Annotation):只有一个成员变量的注解。例如@SuppressWarnings,它用于抑制编译器警告,通常只需要指定抑制的警告类型。
@SuppressWarnings("unchecked")
public class UncheckedExample {
    public void example() {
        List list = new ArrayList();
        list.add("string");
        String s = (String) list.get(0);
    }
}
  • 完整注解(Full - fledged Annotation):包含多个成员变量的注解。开发者可以根据需求为不同的成员变量设置值。

Hibernate框架简介

Hibernate是一个开源的对象关系映射(Object Relational Mapping,ORM)框架,它使得Java开发者可以使用面向对象的方式操作数据库,而无需编写大量的SQL语句。Hibernate的核心功能包括:

  • 对象关系映射:将Java对象与数据库表进行映射,使得可以通过操作Java对象来间接操作数据库中的数据。例如,一个Java类可以映射到数据库中的一张表,类的属性映射到表的列。
  • 数据持久化:负责将Java对象的状态持久化到数据库中,以及从数据库中加载对象的状态。
  • 事务管理:提供了对事务的支持,确保数据库操作的原子性、一致性、隔离性和持久性。

Java注解在Hibernate中的应用

实体类映射注解

  1. @Entity注解:用于将一个Java类声明为Hibernate中的实体类,这个类对应数据库中的一张表。
import javax.persistence.Entity;

@Entity
public class User {
    // 类的属性和方法
}
  1. @Table注解:用于指定实体类对应的数据库表名。如果不使用@Table注解,默认表名与类名相同。通过@Table注解的name属性可以指定表名,catalogschema属性可以分别指定数据库目录和模式。
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "users", catalog = "my_db", schema = "public")
public class User {
    // 类的属性和方法
}
  1. @Id注解:用于指定实体类中的哪个属性作为主键。主键是数据库表中唯一标识一条记录的字段。
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    private Long id;
    // 其他属性和方法
}
  1. @GeneratedValue注解:与@Id注解配合使用,用于指定主键的生成策略。常见的生成策略有IDENTITY(自增长,适用于MySQL等数据库)、SEQUENCE(序列,适用于Oracle等数据库)、AUTO(由Hibernate根据数据库自动选择合适的策略)。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    // 其他属性和方法
}
  1. @Column注解:用于指定实体类属性对应的数据库表列的详细信息,如列名、长度、是否可为空等。
import javax.persistence.Entity;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "username", length = 50, nullable = false)
    private String username;

    @Column(name = "email", length = 100, unique = true)
    private String email;
    // 其他属性和方法
}

关系映射注解

  1. 一对一关系(One - to - One)
    • 单向一对一:使用@OneToOne注解。例如,一个Person实体类可能有一个唯一的Passport实体类与之关联。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToOne
    private Passport passport;
    // 其他方法
}

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Passport {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String number;
    // 其他方法
}
  • 双向一对一:除了@OneToOne注解,还需要在关联的两端设置mappedBy属性来指定关系的维护端。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToOne(mappedBy = "person")
    private Passport passport;
    // 其他方法
}

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class Passport {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String number;

    @OneToOne
    private Person person;
    // 其他方法
}
  1. 一对多关系(One - to - Many)
    • 单向一对多:在“一”的一端使用@OneToMany注解,在“多”的一端使用@ManyToOne注解。例如,一个Department可能有多个Employee
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.List;

@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany
    private List<Employee> employees;
    // 其他方法
}

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne
    private Department department;
    // 其他方法
}
  • 双向一对多:在“一”的一端设置mappedBy属性指向“多”的一端维护关系的属性。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.List;

@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "department")
    private List<Employee> employees;
    // 其他方法
}

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne
    private Department department;
    // 其他方法
}
  1. 多对多关系(Many - to - Many):使用@ManyToMany注解,并且通常需要一个中间表来维护关系。例如,StudentCourse之间可能是多对多关系。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import java.util.List;

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany
    private List<Course> courses;
    // 其他方法
}

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import java.util.List;

@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany(mappedBy = "courses")
    private List<Student> students;
    // 其他方法
}

继承映射注解

  1. @Inheritance注解:用于指定实体类继承体系的映射策略。常见的策略有JOINED(每个子类对应一张表,通过外键关联到父类表)、SINGLE_TABLE(所有子类和父类的数据存储在一张表中,通过一个鉴别器列区分不同的子类)、TABLE_PER_CLASS(每个子类对应一张表,不共享父类表)。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Shape {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    // 其他方法
}

import javax.persistence.Entity;

@Entity
public class Circle extends Shape {
    private double radius;
    // 其他方法
}

import javax.persistence.Entity;

@Entity
public class Rectangle extends Shape {
    private double width;
    private double height;
    // 其他方法
}
  1. @DiscriminatorColumn@DiscriminatorValue注解:当使用SINGLE_TABLE策略时,@DiscriminatorColumn用于指定鉴别器列的名称和类型,@DiscriminatorValue用于指定子类在鉴别器列中的值。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "shape_type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("shape")
public class Shape {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    // 其他方法
}

import javax.persistence.Entity;
import javax.persistence.DiscriminatorValue;

@Entity
@DiscriminatorValue("circle")
public class Circle extends Shape {
    private double radius;
    // 其他方法
}

import javax.persistence.Entity;
import javax.persistence.DiscriminatorValue;

@Entity
@DiscriminatorValue("rectangle")
public class Rectangle extends Shape {
    private double width;
    private double height;
    // 其他方法
}

其他注解

  1. @Transient注解:用于指定一个属性不会被持久化到数据库中。例如,一个计算属性可能不需要存储在数据库中。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Transient;

@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private double price;

    @Transient
    private double discountedPrice;
    // 其他方法
}
  1. @Lob注解:用于表示大对象类型,如Blob(二进制大对象)或Clob(字符大对象)。通常与@Column注解配合使用,指定列的类型。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Column;

@Entity
public class Document {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @Lob
    @Column(columnDefinition = "BLOB")
    private byte[] content;
    // 其他方法
}
  1. @NamedQuery@NamedNativeQuery注解@NamedQuery用于定义命名的JPQL(Java Persistence Query Language)查询,@NamedNativeQuery用于定义命名的原生SQL查询。这些查询可以在整个应用程序中复用。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;

@Entity
@NamedQuery(name = "User.findByUsername", query = "SELECT u FROM User u WHERE u.username = :username")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;
    // 其他方法
}

在使用时,可以通过EntityManager来执行这些命名查询:

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("my_persistence_unit");
        EntityManager em = emf.createEntityManager();

        Query query = em.createNamedQuery("User.findByUsername");
        query.setParameter("username", "testUser");
        List<User> users = query.getResultList();

        em.close();
        emf.close();
    }
}

同样,@NamedNativeQuery的使用方式类似,只是查询语句是原生SQL。

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedNativeQuery;

@Entity
@NamedNativeQuery(name = "User.findByUsernameNative", query = "SELECT * FROM users WHERE username = :username", resultClass = User.class)
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;
    // 其他方法
}

然后可以通过EntityManager执行原生SQL命名查询:

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("my_persistence_unit");
        EntityManager em = emf.createEntityManager();

        Query query = em.createNamedQuery("User.findByUsernameNative");
        query.setParameter("username", "testUser");
        List<User> users = query.getResultList();

        em.close();
        emf.close();
    }
}

通过上述对Java注解在Hibernate中应用的详细介绍,可以看到注解在简化Hibernate配置、实现对象关系映射等方面发挥了重要作用,使得开发者能够更高效地使用Hibernate框架进行数据库相关的开发工作。