Web开发 | Hibernate - 15.Hibernate的JPA注解

本文详细介绍了JPA与Hibernate中的注解使用方法,包括单表和多表的常见注解,如@Entity、@Table、@Id等,并通过实例演示了如何利用这些注解进行数据库表的映射及数据的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  JPA是SUN公司的一个 ORM 规范,只有接口和注解,没有具体实现。JPA是 EJB3 中的子规范。

  Hibernate中有两套注解规范:一套JPA,一套自己的;

  使用注解开发,效率更高。


一、单表常用注解

新建项目Hibernate5_d04_c04,引入必要的jar包、配置、util类


1、简单自动创建一张数据表

  /Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:

package hibernate.domain;

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

@Entity //引入javax.persistence包中的Entity注解
//表示book类是一个实体类
public class Book {
    @Id //对应数据表中的主键
    private Integer id;
    private String name;
    private Double price;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
}

  /Hibernate5_d04_c04/src/hibernate/test/TestBook.java
程序代码如下:

package hibernate.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.domain.Book;
import hibernate.util.HibernateUtils;

public class TestBook {
    //在数据库中自动生成一张数据表
    @Test
    public void testInit(){
        HibernateUtils.getCurrentSession();
    }
}

  /Hibernate5_d04_c04/src/hibernate.cfg.xml
程序代码如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <!-- 必选配置 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
                <!-- jdbc:mysql:///hibernate_day01 -->
        <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate_day04</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
                <!--数据库方言 使用的数据库类型  -->
        <property name="hibernate.dialect org.hibernate.dialect.MySQLDialect"></property>

        <!-- 可选配置 -->
                <!-- 在控制台输出sql语句 -->
        <property name="show_sql">true</property>
                <!-- 在控制台输出的sql语句格式化 -->
        <property name="hibernate.format_sql">true</property>
                <!-- 配置c3p0连接池 -->
                    <!-- C3P0 的供应商 -->
        <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
                    <!-- 最小连接 -->
        <property name="hibernate.c3p0.min_size">5</property>
                    <!-- 最大连接数 -->
        <property name="hibernate.c3p0.max_size">10</property>
                    <!-- 每 120 秒检查空闲连接 -->
        <property name="hibernate.c3p0.timeout">120</property>
                <!-- 自动建表 -->
        <property name="hibernate.hbm2ddl.auto">update</property>
                <!-- 把session绑定到当前线程中,使用getCurrentSession()获取当前session -->
        <property name="hibernate.current_session_context_class">thread</property>

        <!-- 映射文件 -->
        <!-- 关联 xml 配置文件,注解方式配置 -->
        <!-- 单表 -->
        <mapping class="hibernate.domain.Book"/>
    </session-factory>
</hibernate-configuration>

运行效果
运行效果


2、保存数据

  /Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:

package hibernate.domain;

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

@Entity //引入javax.persistence包中的Entity注解
//表示book类是一个实体类
public class Book {
    @Id //对应数据表中的主键
    //主键生成策略
    //AUTO = native
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    private Double price;


    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
}

  /Hibernate5_d04_c04/src/hibernate/test/TestBook.java
程序代码如下:

package hibernate.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.domain.Book;
import hibernate.util.HibernateUtils;

public class TestBook {
    //在数据表中插入一条数据
    @Test
    public void testSave(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        Book book = new Book();
        book.setName("西游记");
        book.setPrice(88.88);
        session.save(book);
        tr.commit();
    }
}

运行结果


3、指定操作某个表

  /Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:

package hibernate.domain;

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

@Entity //引入javax.persistence包中的Entity注解
//表示book类是一个实体类
@Table(name="t_book") //指定操作某个表
public class Book {
    @Id //对应数据表中的主键
    //主键生成策略
    //AUTO = native
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    private Double price;
    ...
}

运行效果
运行效果


4、更多常用注解

  @Entity //注意引入的包名为javax.persistence.Entity

  注解:可以放到属性声明上面设置,也可以在getter方法上设置,效果一样。但是:要么都放属性,要么都放getter,不能混着用。


推荐标准最小化配置

//po实体类
@Entity //指定该po对象为实体对象,对应表
@Table(name="t_book") //类似:table="t_book"
public class Book {
    @Id //指定该字段是主键,注解也可以写在getter方法上
    //主键生成策略
    //@GeneratedValue默认是自适应的主键策略:strategy=GenerationType.AUTO
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    private Double price;
    ...
    getter和setter方法
}

实体和表本身相关
实体和表本身相关


主键相关的
主键相关的

Auto 相当与 native,默认值


自定义主键策略(使用Hibernate实现)

  /Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:

...
public class Book {
    @Id //指定该字段是主键,直接也可以写在getter方法上
    //@GeneratedValue //默认是自适应的主键策略:strategy=GenerationType.AUTO
    //@GeneratedValue(strategy=GenerationType.AUTO) //有点像native
    @GenericGenerator(name="myIdGenerator",strategy="uuid")  //主键策略生成器,name:是主键策略的名字,给下面用
    @GeneratedValue(generator="myIdGenerator") //generator:指定一个具体的主键策略,可以自定义
    private Integer id;
    ...
}

其他字段相关的

  /Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:

...
public class Book {
    ...
    //如果不加任何注解,则默认的属性名就是字段名
    @Column(name="bname",length=30,nullable=false,unique=true) //name:字段名字
    private String name;
    //忽略属性:该属性不想映射为字段
    @Transient //该属性不会作为数据库字段
    private Double price;
    ...
}

属性字段官方参考配置

name 可选。列名(默认是属性名)
unique 可选。是否在该列上设置唯一约束(默认值false)
nullable 可选。是否设置该列的值可以为空(默认值false)
insertable 可选。该列是否作为生成的insert语句中的一个列(默认值true)
updatable 可选。该列是否作为生成的update语句中的一个列(默认值true)
columnDefinition 可选。为这个特定列覆盖SQL DDL片段(这可能导致无法在不同数据库间移植)
table 可选。定义对应的表(默认为主表)
length 可选。列长度(默认值255)
precision 可选。列十进制精度(decimal precision)(默认值0)
scale 可选。如果列十进制数值范围(decimal scale)可用,在此设置(默认值0)

较完整配置

  /Hibernate5_d04_c04/src/hibernate/domain/Book.java
程序代码如下:

...
//po实体类
@Entity //将当前类标识为一个实力类po,表名,默认就是实体类的名字
@Table(name="t_book",catalog="hb21")//table="t_book"
public class Book {
    @Id //将当前字段标识为一个oid的属性,主键,主键策略默认为自动(根据数据库自动适应)
    //@GeneratedValue //默认值是auto,相当于native
    //@GeneratedValue(strategy=GenerationType.AUTO) //jpa内置的主键策略
    //Hibernate的主键策略生成器,name:是主键策略生成器的名字,strategy:Hibernate的主键策略
    @GenericGenerator(name="myIdGenerator",strategy="assigned") 
    @GeneratedValue(generator="myIdGenerator") //generator使用自定义扩展的主键生成器
    private Integer id;
    @Column(name="bname",length=30,unique=true)
    //@Basic //该字段有效
    private String name;
    //Hibernate就不会将该属性作为字段的映射,忽略了该字段
    @Transient
    private Double price;
    ...
}

二、多表常用注解之一对多

1、注解案例

  /Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:

package hibernate.domain;

import java.util.HashSet;
import java.util.Set;

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

@Entity
@Table(name="t_customer")
public class Customer {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    private String city;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
}

  /Hibernate5_d04_c04/src/hibernate/domain/Order.java
程序代码如下:

package hibernate.domain;

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

@Entity
@Table(name="t_order")
public class Order {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    private Double price;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
}

  /Hibernate5_d04_c04/src/hibernate.cfg.xml
程序代码如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <!-- 必选配置 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
                <!-- jdbc:mysql:///hibernate_day01 -->
        <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate_day04</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
                <!--数据库方言 使用的数据库类型  -->
        <property name="hibernate.dialect org.hibernate.dialect.MySQLDialect"></property>

        <!-- 可选配置 -->
                <!-- 在控制台输出sql语句 -->
        <property name="show_sql">true</property>
                <!-- 在控制台输出的sql语句格式化 -->
        <property name="hibernate.format_sql">true</property>
                <!-- 配置c3p0连接池 -->
                    <!-- C3P0 的供应商 -->
        <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
                    <!-- 最小连接 -->
        <property name="hibernate.c3p0.min_size">5</property>
                    <!-- 最大连接数 -->
        <property name="hibernate.c3p0.max_size">10</property>
                    <!-- 每 120 秒检查空闲连接 -->
        <property name="hibernate.c3p0.timeout">120</property>
                <!-- 自动建表 -->
        <property name="hibernate.hbm2ddl.auto">update</property>
                <!-- 把session绑定到当前线程中,使用getCurrentSession()获取当前session -->
        <property name="hibernate.current_session_context_class">thread</property>

        <!-- 映射文件 -->
        <!-- 关联 xml 配置文件,注解方式配置 -->
        <!-- 一对多 -->
        <mapping class="hibernate.domain.Customer"/>
        <mapping class="hibernate.domain.Order"/>
    </session-factory>
</hibernate-configuration>

配置一对多

  /Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:

...
@Entity
@Table(name="t_customer")
public class Customer {
    ...
    //一对多
    @OneToMany
    private Set<Order> orders = new HashSet<>();

    ...

    public Set<Order> getOrders() {
        return orders;
    }
    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }
}

  /Hibernate5_d04_c04/src/hibernate/domain/Order.java
程序代码如下:

...
@Entity
@Table(name="t_order")
public class Order {
    ...
    //多对一
    @ManyToOne
    private Customer customer;

    ...

    public Customer getCustomer() {
        return customer;
    }
    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}

  /Hibernate5_d04_c04/src/hibernate/test/TestOne2Many.java
程序代码如下:

package hibernate.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.domain.Customer;
import hibernate.domain.Order;
import hibernate.util.HibernateUtils;

public class TestOne2Many {
    //保存数据
    @Test
    public void testOne2Many(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        //新建一个客户
        Customer c = new Customer();
        c.setName("冠希");

        //新建2个订单
        Order o1 = new Order();
        o1.setName("摄像机");

        Order o2 = new Order();
        o2.setName("电脑");

        //双向关联
        c.getOrders().add(o1);
        c.getOrders().add(o2);

        o1.setCustomer(c);
        o2.setCustomer(c);

        //保存操作
        session.save(o1);
        session.save(o2);
        session.save(c);

        tr.commit();
    }
}

运行效果
运行效果

从数据库中可以知道,Hibernate会自动生成一张中间表,我们可以通过注解去掉这个中间表

  /Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:

...
@Entity
@Table(name="t_customer")
public class Customer {
    ...
    //一对多
    //mappedBy 除去中间表
    //mappedBy 是关联对象Order类在自己的实体类中一方的属性(需要在一方配置)
    //mappedBy="customer" 会在order表中生成一个外键,这里将生成叫customer_id的外键
    @OneToMany(mappedBy="customer")
    private Set<Order> orders = new HashSet<>();
    ...
}

运行效果


2、更多配置

  /Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:

...
public class Customer {
    ...

    //关系:注解都直接配置关系
    //@OneToMany(mappedBy="customer") //mappedBy是关联属性order在自己的实体类中的一方的属性(需要在一方配置)
    //它会自动将Customer的主键作为外键,并且,自动将外键名称设置为:实体类小写_id
    @OneToMany(cascade=CascadeType.ALL //级联
            ,fetch=FetchType.LAZY //是否懒加载
            ,orphanRemoval=true //是否支持孤儿删除
            ,mappedBy="Customer" //关系对象中关系属性的名字
            ,targetEntity=hibernate.domain.Order.class //关联属性的实体类的名字(全名),一般忽略。
            //某些情况下不能忽略,Order如果是个借口,不是具体的实现的情况下,这里就要配置具体的实现类
            )
    private Set<Order> orders = new HashSet<>();

    ...
}

  /Hibernate5_d04_c04/src/hibernate/domain/Order.java
程序代码如下:

...

@Entity
@Table(name="t_order")
public class Order {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    private Double price;

    //关系
    @ManyToOne
    @JoinColumn(name="c_id") //在关系(对象)表中配置外键名称,如果不配置,默认:实体类小写_id
    private Customer customer;

    ...
}

三、多表常用注解之多对多

1、注解案例

  /Hibernate5_d04_c04/src/hibernate/domain/Student.java
程序代码如下:

package hibernate.domain;

import java.util.HashSet;
import java.util.Set;

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

@Entity
@Table(name="t_student")
public class Student {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    //多对多
    @ManyToMany
    private Set<Course> courses = new HashSet<>();

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Set<Course> getCourses() {
        return courses;
    }
    public void setCourses(Set<Course> courses) {
        this.courses = courses;
    }


}

  /Hibernate5_d04_c04/src/hibernate/domain/Course.java
程序代码如下:

package hibernate.domain;

import java.util.HashSet;
import java.util.Set;

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

@Entity
@Table(name="t_course")
public class Course {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
    //多对多
    @ManyToMany
    private Set<Student> students = new HashSet<>();


    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}

  /Hibernate5_d04_c04/src/hibernate/test/TestMany2Many.java
程序代码如下:

package hibernate.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.domain.Course;
import hibernate.domain.Student;
import hibernate.util.HibernateUtils;

public class TestMany2Many {
    @Test
    public void testMany2Many(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        //新建一个学生
        Student s = new Student();
        s.setName("冠希");

        //新建一门课程
        Course c = new Course();
        c.setName("摄影");

        //双向关联
        s.getCourses().add(c);
        c.getStudents().add(s);

        //保存
        session.save(c);
        session.save(s);


        tr.commit();
    }
}

  /Hibernate5_d04_c04/src/hibernate.cfg.xml
程序代码如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <!-- 必选配置 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
                <!-- jdbc:mysql:///hibernate_day01 -->
        <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate_day04</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
                <!--数据库方言 使用的数据库类型  -->
        <property name="hibernate.dialect org.hibernate.dialect.MySQLDialect"></property>

        <!-- 可选配置 -->
                <!-- 在控制台输出sql语句 -->
        <property name="show_sql">true</property>
                <!-- 在控制台输出的sql语句格式化 -->
        <property name="hibernate.format_sql">true</property>
                <!-- 配置c3p0连接池 -->
                    <!-- C3P0 的供应商 -->
        <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
                    <!-- 最小连接 -->
        <property name="hibernate.c3p0.min_size">5</property>
                    <!-- 最大连接数 -->
        <property name="hibernate.c3p0.max_size">10</property>
                    <!-- 每 120 秒检查空闲连接 -->
        <property name="hibernate.c3p0.timeout">120</property>
                <!-- 自动建表 -->
        <property name="hibernate.hbm2ddl.auto">update</property>
                <!-- 把session绑定到当前线程中,使用getCurrentSession()获取当前session -->
        <property name="hibernate.current_session_context_class">thread</property>

        <!-- 映射文件 -->
        <!-- 关联 xml 配置文件,注解方式配置 -->
        <!-- 多对多 -->
        <mapping class="hibernate.domain.Course"/>
        <mapping class="hibernate.domain.Student"/>
    </session-factory>
</hibernate-configuration>

运行效果

从数据库中可以知道,Hibernate会自动生成两张中间表,我们可以通过注解去掉其中一张中间表

  * *
程序代码如下:

...
@Entity
@Table(name="t_course")
public class Course {
    ...
    //多对多
    //mappedBy只会生成一张中间表
    //必须在某一方配置外键关联字段
    //mappedBy="courses" 对应Student类中的Set<Course> courses
    //应该配置中间表的信息
    //如果不配置,默认中间表的名字就是表名 1_表名 2,字段是各自的:实体类名字_id
    @ManyToMany(mappedBy="courses")
    private Set<Student> students = new HashSet<>();
    ...
}

运行效果


2、更多配置

  /Hibernate5_d04_c04/src/hibernate/domain/Student.java
程序代码如下:

...
@Entity
@Table(name="t_student")
public class Student {
    @Id
    @GeneratedValue
    private Integer id;
    private String name;

    //多对多关系
    @ManyToMany
    //应该配置中间表的信息,如果不配置,默认的中间表的名字就是:表名1_表名2,字段是各自的:实体类字段_id
    @JoinTable(name="t_student_course" //自定义中间关系表信息,name:中间表的名字
                ,joinColumns=@JoinColumn(name="s_id") //自己在关系表中的外键的名字
                ,inverseJoinColumns={@JoinColumn(name="c_id")} //对方在关系表中外键的名称
            )
    private Set<Course> courses = new HashSet<>();

    ...
}

  /Hibernate5_d04_c04/src/hibernate/domain/Course.java
程序代码如下:

...

@Entity
@Table(name="t_course")
public class Course {
    @Id
    @GeneratedValue
    private Integer id;
    private String name;
    //多对多关系
    @ManyToMany(mappedBy="courses") //外键维护权,多表只能在一方配置
    //必须在某一方面配置外键关联字段
    private Set<Student> students = new HashSet<>();

    ...
}

四、抓取策略注解

.在一方Customer类中配置抓取策略

  /Hibernate5_d04_c04/src/hibernate/test/TestFetch.java
程序代码如下:

package hibernate.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import hibernate.domain.Customer;
import hibernate.util.HibernateUtils;

public class TestFetch {
    @Test
    public void testFetch(){
        //获取11号客户
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        Customer c = session.get(Customer.class, 11);
        //获取客户对应的所有订单数量
        System.out.println(c.getName()+"-->"+c.getOrders().size());

        tr.commit();
    }
}

  /Hibernate5_d04_c04/src/hibernate/domain/Customer.java
程序代码如下:

...
@Entity
@Table(name="t_customer")
public class Customer {
    ...
    @OneToMany(mappedBy="customer")
    //配置抓取策略
    @Fetch(FetchMode.JOIN)
    @LazyCollection(LazyCollectionOption.TRUE)
    private Set<Order> orders = new HashSet<>();
    ...
}

配置抓取策略前

运行效果
发送两条SQL语句


配置抓取策略后

运行效果

内容概要:本文深入解析了扣子COZE AI编程及其详细应用代码案例,旨在帮助读者理解新一代低门槛智能体开发范式。文章从五个维度展开:关键概念、核心技巧、典型应用场景、详细代码案例分析以及未来发展趋势。首先介绍了扣子COZE的核心概念,如Bot、Workflow、Plugin、Memory和Knowledge。接着分享了意图识别、函数调用链、动态Prompt、渐进式发布及监控可观测等核心技巧。然后列举了企业内部智能客服、电商导购助手、教育领域AI助教和金融行业合规质检等应用场景。最后,通过构建“会议纪要智能助手”的详细代码案例,展示了从需求描述、技术方案、Workflow节点拆解到调试与上线的全过程,并展望了多智能体协作、本地私有部署、Agent2Agent协议、边缘计算插件和实时RAG等未来发展方向。; 适合人群:对AI编程感兴趣的开发者,尤其是希望快速落地AI产品的技术人员。; 使用场景及目标:①学习如何使用扣子COZE构建生产级智能体;②掌握智能体实例、自动化流程、扩展能力和知识库的使用方法;③通过实际案例理解如何实现会议纪要智能助手的功能,包括触发器设置、下载节点、LLM节点Prompt设计、Code节点处理和邮件节点配置。; 阅读建议:本文不仅提供了理论知识,还包含了详细的代码案例,建议读者结合实际业务需求进行实践,逐步掌握扣子COZE的各项功能,并关注其未来的发展趋势。
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:471) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final] at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1498) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final] at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.26.jar:5.3.26] at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.26.jar:5.3.26] at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-5.3.26.jar:5.3.26] at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[spring-orm-5.3.26.jar:5.3.26] at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) ~[spring-orm-5.3.26.jar:5.3.26] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.26.jar:5.3.26] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.26.jar:5.3.26] ... 16 more
03-22
<think>嗯,用户遇到了Hibernate和Spring整合时SessionFactory创建失败的问题,具体提到了hibernate-core-5.6.15.Final和spring-orm-5.3.26版本。我需要先分析可能的原因,再给出解决步骤。 首先,版本兼容性可能是个问题。Hibernate和Spring的版本需要兼容,特别是spring-orm和hibernate-core之间的依赖。检查官方文档或Maven仓库的兼容性信息,确认这两个版本是否匹配。比如,Spring 5.3.x通常支持Hibernate 5.4到5.6,但具体小版本可能会有问题,需要确认是否有已知的冲突。 其次,配置文件的正确性。用户提到引用了hibernate.cfg.xml的配置,可能存在配置错误。比如数据库连接参数是否正确,驱动类是否匹配,尤其是时区设置和SSL设置。例如,MySQL 8.0需要时区设置,或者SSL连接可能需要禁用,如果未正确配置,会导致连接失败,进而SessionFactory无法创建。 第三,依赖冲突也是一个常见问题。检查项目的依赖树,是否有多个不同版本的Hibernate或Spring模块被引入。比如,可能同时存在hibernate-core的不同版本,或者Spring的其他模块版本不一致,导致类加载问题。使用Maven的依赖树命令(mvn dependency:tree)可以帮助识别冲突。 另外,日志信息是关键。用户需要查看完整的异常堆栈信息,可能包括类找不到、方法不存在,或者数据库连接超时等。例如,引用中的lock_wait_timeout和interactive_timeout可能与数据库连接配置有关,但具体错误需要根据日志来判断。比如,InnoDB关闭的日志可能表明数据库服务未正常运行,或者连接被拒绝。 还有,Spring的配置方式是否正确。如果使用注解配置,是否遗漏了必要的注解如@Configuration,@EnableTransactionManagement,或者数据源配置是否正确注入。例如,LocalSessionFactoryBean是否正确设置了dataSource和hibernateProperties。 最后,考虑数据库服务本身的状态。检查MySQL是否在运行,端口是否正确,权限是否足够。引用中的server_id和skip_name_resolve可能涉及主从配置或网络设置,如果配置错误可能导致连接问题。 总结下来,解决步骤应该是先检查版本兼容性,然后查看日志确定具体错误,接着核对配置文件和依赖,最后确保数据库服务正常。可能需要逐步排除,从版本调整到配置修正,再到依赖清理。</think>以下是解决Hibernate与Spring整合时SessionFactory创建失败问题的逐步排查与解决方案: --- ### 一、版本兼容性问题 1. **检查Hibernate与Spring版本匹配性** - **Hibernate 5.6.x** 需要与 **Spring 5.3.x** 的特定子版本兼容。已知 `spring-orm-5.3.26` 与 `hibernate-core-5.6.15` 可能存在兼容性问题,建议尝试以下组合: ```xml <!-- 升级Spring至5.3.28或降级Hibernate至5.6.14 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.3.28</version> </dependency> ``` - 若仍失败,尝试强制对齐其他依赖项(如 `hibernate-validator`、`spring-core`)的版本[^1]。 2. **JDK版本适配** 确认项目JDK版本支持Hibernate 5.6(需JDK 8+)。 --- ### 二、配置文件分析 1. **检查`hibernate.cfg.xml`或`application.properties`** - 确保数据库连接参数正确,例如: ```xml <!-- hibernate.cfg.xml示例 --> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/db?useSSL=false&serverTimezone=UTC</property> <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property> ``` - 注意MySQL 8.0+需使用`com.mysql.cj.jdbc.Driver`并添加时区参数[^2]。 2. **Spring配置注入问题** - 若通过Spring配置,检查`LocalSessionFactoryBean`定义: ```java @Bean public LocalSessionFactoryBean sessionFactory(DataSource dataSource) { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setPackagesToScan("com.example.model"); sessionFactory.setHibernateProperties(hibernateProperties()); return sessionFactory; } ``` --- ### 三、依赖冲突排查 1. **检查依赖树** 执行以下命令查看冲突: ```bash mvn dependency:tree -Dincludes=org.hibernate,org.springframework ``` - 若存在多个版本的Hibernate或Spring模块(如`hibernate-entitymanager`与`hibernate-core`版本不一致),需通过`<exclusion>`排除冗余依赖。 2. **常见冲突示例** - **C3P0连接池冲突**:Hibernate 5.6默认使用HikariCP,若项目强制依赖C3P0需显式配置: ```xml <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.5</version> </dependency> ``` --- ### 四、日志与错误分析 1. **启用完整日志** 在`log4j.properties`中添加: ```properties log4j.logger.org.hibernate=DEBUG log4j.logger.org.springframework=DEBUG ``` - 观察错误堆栈中的具体类名和方法,例如: - `NoSuchMethodError`:类版本不匹配。 - `Connection refused`:数据库服务未启动或端口错误[^3]。 2. **典型错误场景** - **数据库连接超时**:检查`wait_timeout`和`interactive_timeout`参数,确保连接池配置合理。 - **方言(Dialect)未设置**:在配置中添加: ```xml <property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property> ``` --- ### 五、验证步骤 1. **最小化测试** 创建一个仅包含Hibernate+Spring核心依赖的测试项目,逐步添加配置验证功能。 2. **数据库连通性验证** 使用独立JDBC代码测试数据库连接,排除网络或权限问题。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值