Hibernate学习笔记4

Hibernate–4

JPA(Java Persistence API):Java持久化API,用于规范ORM接口的一系列规范。

Hibernate中实现了JPA规范

配置

  • 项目引入jpa配置(persistence.xml)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?xml version="1.0" encoding="UTF-8" ?>
    <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
    http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
    version="2.1">
    <!--
    name : 用于指定持久化单元的名称(可以为空,必须配)
    transaction-type : 指定事务类型,取值为JTA(默认)、RESOURCE_LOCAL
    -->
    <persistence-unit name="Unit1" transaction-type="RESOURCE_LOCAL">

    <!--javax.persistence.PersistenceProvider的一个实现类,用于创建EntityManagerFactory(用于产生实体类管理者工厂)-->
    <!--在Hibernate中实现了JPA规范,这个类其实也是默认的,可以不配-->
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <!--罗列出需要持久化的类(在JavaEE环境下可以不配)-->
        <class>com.lee.cfgtest.Student</class>
        <class>com.lee.cfgtest.Teacher</class>
    
        <class>com.lee.one2many.Tenant</class>
        <class>com.lee.one2many.Landlord</class>
    
        <!--JPA实现者专有配置,不同的JPA规范实现框架,可能配置的property值不一样-->
        <!--参考hibernate.cfg.xml中的配置-->
        <properties>
            <!--DDL生成策略-->
            <!--其中update表示:检测实体类和表结构是否一致,如果不一致,更新表结构达到一致,如果不存在该表,就创建一张表-->
            <property name="hibernate.hbm2ddl.auto" value="update"/>
    
            <!--第一部分:数据库连接配置-->
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/hibernate2"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="123"/>
    
            <!--第二部分 :配置数据库连接池:c3p0 (自由选择)-->
            <property name="hibernate.connection.provider_class"
                      value="org.hibernate.connection.C3P0ConnectionProvider"/>
            <!--配置数据库方言-->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL55Dialect"/>
            <!--是否在控制台显示生成的sql语句-->
            <property name="hibernate.show_sql" value="true"/>
            <!--是否将控制台里的sql语句格式化输出-->
            <!--<property name="hibernate.format_sql" value="true"/>-->
    
        </properties>
    </persistence-unit>
    

    一对多关系配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
* 实体类中的配置(包含表之间一对多映射配置)

一对多关系中的"一"的一方实体类配置

@Entity
@Table(name = "hb_landlord")
public class Landlord {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "l_id")
private Integer lid;

@Column(name = "l_name")
private String lname;

@Column(name = "l_sex")
private String lsex;
@Column(name = "l_age")
private Integer lage;
@Column(name = "l_phone")
private String lphone;

// 参数解释:
// targetEntity:表示对应的"多"的一方的字节码文件,也可以不加
// mappedBy:从表中引用的该实体属性名,如果配置了该项,表示放弃维护和从表之间的关联关系.在一对多配置中,一般"一"的一方会配置上该属性;如果没有配置该属性,会生成第三张表(类似于多对多中的中间表)来维护他们之间的关系
// fetch:配置tenants的加载方式, OneToMany中fetch的默认值为LAZY
// 还有其他属性:cascade:级联操作
@OneToMany(targetEntity = Tenant.class, fetch = FetchType.LAZY, mappedBy = "landlord")
private Set<Tenant> tenants = new HashSet<>(0);

// 省略默认构造方法,get/set方法,toString()方法
}

注意:属性级别的注解,都是放在其对应的getter前。

一对多中”多”的一方的实体类配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Entity
@Table(name = "hb_tenant")
public class Tenant {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "t_id")
private Integer tid;
@Column(name = "t_name")
private String tname;
@Column(name = "t_sex")
private String tsex;
@Column(name = "t_age")
private Integer tage;
@Column(name = "t_phone")
private String tphone;
@Column(name = "t_job")
private String tjob; // 从事的工作

// 一位租户只能有一个房东,建立关系
@ManyToOne(targetEntity = Landlord.class, fetch = FetchType.LAZY)
// 用于配置外键,如果不配置也会默认生成(最好自己配上,生成的外键字段可读性更好)
@JoinColumn(name = "land_tenant_fk", referencedColumnName = "l_id")
private Landlord landlord;

// 省略默认构造方法,get/set方法,toString()方法
}

多对多关系配置

多对多配置以后会生成一个中间表,中间表维护了两个表之间的关系.但是在配置的时候,要分清楚关系维护端(保留关联关系),任何两个表之间都有主从之分

主表:hb_teacher对应的实体表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Entity // 指定这是一个实体类.在创建EntityManagerFactory的时候就会读取映射配置
@Table(name = "hb_teacher") // 指定该表所在数据库中的表名
public class Teacher {

@Id // 主键
@GeneratedValue(strategy = GenerationType.IDENTITY) // 主键生成策略
@Column(name = "t_id") // 主键在数据库中对应的字段名
private Long tid;


@Column(name = "t_name")
private String tname;

@Column(name = "t_age")
private String tage;

// targetEntity:映射的另一方实体的类
// mappedBy : 被对方维护关联关系(也就是说放弃了维护关联关系的权利)
@ManyToMany(targetEntity = Student.class,mappedBy = "teachers")
private Set<Student> students = new HashSet<>(0);

public Teacher() {
}

// 省略get/set方法,省略toString方法
}

从表:hb_student表对应的实:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Entity
@Table(name = "hb_student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "s_id")
private Long sid;

@Column(name = "s_name")
private String sname;

@Column(name = "s_age")
private String sage;

@ManyToMany(targetEntity = Teacher.class)
@JoinTable(
name = "stu_tea_ref", // 中间表的表名
joinColumns = {
// 指定自己一方在表中维护的字段.name:字段名;referencedColumnName:关联的字段名称
@JoinColumn(name = "stu_id", referencedColumnName = "s_id")
},
inverseJoinColumns = {
// 指定对方在表中维护的字段.name:字段名;referencedColumnName:关联的字段的名称
@JoinColumn(name = "tea_id", referencedColumnName = "t_id")
}
)
private Set<Teacher> teachers = new HashSet<>(0);

public Student() {
}

// 省略get/set方法,省略toString()方法
}

在执行删除操作时:

主控方(维护了关联关系的表):

  • 可以同时将记录删除,并且删除中间表中的记录

从方(放弃维护关联关系的表):

  • 如果该记录被中间表引用,不能删除
  • 在从方配置了级联删除,会将该记录删除,中间表中的数据也会删除,但,同时会将主控方的表中也删除一条记录,这是不允许的