Hibernate学习(3) (继承映射,配置文件和注解版)

来源:互联网 发布:ubuntu 字体路径 编辑:程序博客网 时间:2024/06/08 07:13

这篇blog准备写怎样在Hibernate中反应内存对象之间的继承关系.我们知道,内存对象之间是可以有继承关系的,但是在数据库中,我们继承神马的都是浮云,不存在的.那么怎么办呢?Hibernate提供了继承关系映射!(其实就是帮你把原来的一个类以一种特定的方式存储在数据库中.)
我们以官方的例子为例:
这里写图片描述
分为四种方式:
1. MappedSuperclass
被继承的表在数据库中不映射.

    @MappedSuperclasspublic static class Account {    @Id    private Long id;    private String owner;    private BigDecimal balance;    private BigDecimal interestRate;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getOwner() {        return owner;    }    public void setOwner(String owner) {        this.owner = owner;    }    public BigDecimal getBalance() {        return balance;    }    public void setBalance(BigDecimal balance) {        this.balance = balance;    }    public BigDecimal getInterestRate() {        return interestRate;    }    public void setInterestRate(BigDecimal interestRate) {        this.interestRate = interestRate;    }}@Entity(name = "DebitAccount")public static class DebitAccount extends Account {    private BigDecimal overdraftFee;    public BigDecimal getOverdraftFee() {        return overdraftFee;    }    public void setOverdraftFee(BigDecimal overdraftFee) {        this.overdraftFee = overdraftFee;    }}@Entity(name = "CreditAccount")public static class CreditAccount extends Account {    private BigDecimal creditLimit;    public BigDecimal getCreditLimit() {        return creditLimit;    }    public void setCreditLimit(BigDecimal creditLimit) {        this.creditLimit = creditLimit;    }}   
CREATE TABLE DebitAccount (    id BIGINT NOT NULL ,    balance NUMERIC(19, 2) ,    interestRate NUMERIC(19, 2) ,    owner VARCHAR(255) ,    overdraftFee NUMERIC(19, 2) ,    PRIMARY KEY ( id ))CREATE TABLE CreditAccount (    id BIGINT NOT NULL ,    balance NUMERIC(19, 2) ,    interestRate NUMERIC(19, 2) ,    owner VARCHAR(255) ,    creditLimit NUMERIC(19, 2) ,    PRIMARY KEY ( id ))

没有创建Acount表,但是Account的属性在每个子类的数据库表中都存在.
2. Single table
单表映射,所有的类映射到数据库中的一个表
Annotation版本:

@Entity(name = "Account")@Inheritance(strategy = InheritanceType.SINGLE_TABLE)public static class Account {    @Id    private Long id;    private String owner;    private BigDecimal balance;    private BigDecimal interestRate;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getOwner() {        return owner;    }    public void setOwner(String owner) {        this.owner = owner;    }    public BigDecimal getBalance() {        return balance;    }    public void setBalance(BigDecimal balance) {        this.balance = balance;    }    public BigDecimal getInterestRate() {        return interestRate;    }    public void setInterestRate(BigDecimal interestRate) {        this.interestRate = interestRate;    }}@Entity(name = "DebitAccount")public static class DebitAccount extends Account {    private BigDecimal overdraftFee;    public BigDecimal getOverdraftFee() {        return overdraftFee;    }    public void setOverdraftFee(BigDecimal overdraftFee) {        this.overdraftFee = overdraftFee;    }}@Entity(name = "CreditAccount")public static class CreditAccount extends Account {    private BigDecimal creditLimit;    public BigDecimal getCreditLimit() {        return creditLimit;    }    public void setCreditLimit(BigDecimal creditLimit) {        this.creditLimit = creditLimit;    }}
CREATE TABLE Account (    DTYPE VARCHAR(31) NOT NULL ,    id BIGINT NOT NULL ,    balance NUMERIC(19, 2) ,    interestRate NUMERIC(19, 2) ,    owner VARCHAR(255) ,    overdraftFee NUMERIC(19, 2) ,    creditLimit NUMERIC(19, 2) ,    PRIMARY KEY ( id ))

Account Table:

DTYPE id balance owner interestRate overdraftFee creditLimit 描述列(表明这是什么类的实例对象) 主键 Account属性 Account属性 Account属性 DebitAccount属性(CreditAccount中为空) CreditAccount属性(在DebitAccount中为空)

Single table版本,需要在Account表格中添加所有子类可能的属性以及对于类的描述性列(,因为子父类都在一个表中,我们需要知道一个元组是什么类,所以必须有一个描述列更多关于描述列,这里DTYPE即是它的描述性列,只能为String,Char,INTEGER),因此会有大量的数据冗余.

注解版本使用另外三个类:
Plane(父类),Airbus(子类),Boeing(子类)

public class Plane {    private Long id;    private String type;    private String manufacturer;    public Plane() {}    public Long getId() { return id; }    private void setId(Long id) { this.id = id; }    public String getType() { return type; }    public void setType(String type) {         this.type = type;     }    public String getManufacturer() {         return manufacturer;    }    public void setManufacturer(String manufacturer) {        this.manufacturer = manufacturer;    }}public class Airbus extends Plane{    private String capacity;    public Airbus() {}    public String getCapacity() { return capacity; }    private void setCapacity(String capacity) {         this.capacity = capacity;     }}public class Boeing extends Plane{    private String comfort;    public Boeing() {}    public String getComfort() { return comfort; }    private void setComfort(String comfort) {         this.comfort = comfort;     }}

配置文件:

<hibernate-mapping package="Sample.Entity"discriminator-value="0“ >    <class name="Plane" table="planes">        <id name="id" column="ID">            <generator class="native"/>        </id>        <discriminator column="DISC" type="string"/>        <property name="type"/>        <property name="manufacturer"/>        <subclass name="Airbus" discriminator-value="1">            <property name="capacity" />        </subclass>        <subclass name="Boeing" discriminator-value="2">            <property name="comfort" />        </subclass>    </class></hibernate-mapping>

这里写图片描述

优点:效率最高,不需要多表联合查询.
缺点:会产生太多的数据冗余,大量的null字段,导致完整性约束不能在数据库层面上使用,只能依靠数据操作层维持.
3. Joined table

@Entity(name = "Account")@Inheritance(strategy = InheritanceType.JOINED)public static class Account {    @Id    private Long id;    private String owner;    private BigDecimal balance;    private BigDecimal interestRate;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getOwner() {        return owner;    }    public void setOwner(String owner) {        this.owner = owner;    }    public BigDecimal getBalance() {        return balance;    }    public void setBalance(BigDecimal balance) {        this.balance = balance;    }    public BigDecimal getInterestRate() {        return interestRate;    }    public void setInterestRate(BigDecimal interestRate) {        this.interestRate = interestRate;    }}@Entity(name = "DebitAccount")public static class DebitAccount extends Account {    private BigDecimal overdraftFee;    public BigDecimal getOverdraftFee() {        return overdraftFee;    }    public void setOverdraftFee(BigDecimal overdraftFee) {        this.overdraftFee = overdraftFee;    }}@Entity(name = "CreditAccount")public static class CreditAccount extends Account {    private BigDecimal creditLimit;    public BigDecimal getCreditLimit() {        return creditLimit;    }    public void setCreditLimit(BigDecimal creditLimit) {        this.creditLimit = creditLimit;    }}
CREATE TABLE Account (    id BIGINT NOT NULL ,    balance NUMERIC(19, 2) ,    interestRate NUMERIC(19, 2) ,    owner VARCHAR(255) ,    PRIMARY KEY ( id ))CREATE TABLE CreditAccount (    creditLimit NUMERIC(19, 2) ,    id BIGINT NOT NULL ,    PRIMARY KEY ( id ))CREATE TABLE DebitAccount (    overdraftFee NUMERIC(19, 2) ,    id BIGINT NOT NULL ,    PRIMARY KEY ( id ))ALTER TABLE CreditAccountADD CONSTRAINT FKihw8h3j1k0w31cnyu7jcl7n7nFOREIGN KEY (id) REFERENCES AccountALTER TABLE DebitAccountADD CONSTRAINT FKia914478noepymc468kiaivqmFOREIGN KEY (id) REFERENCES Account

创建了三个表格,子表中只存在子类的自身属性加上父类的外键约束.
因为在查询的时候,语句大约是:

    select ...    from Account    ... Join DebitAccount    ... Join CreditAccount.

这种策略使用join 操作父子类表.
配置文件版本:

public class Cat {    private Long uid;    private Date birthday;    private String color;    private String sex;    private int weight;    public Cat() {    }    public Long getUid() {        return uid;    }    private void setUid(Long uid) {        this.uid = uid;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    public String getColor() {        return color;    }    public void setColor(String color) {        this.color = color;    }    public String getSex() {        return sex;    }    public void setSex(String sex) {        this.sex = sex;    }    public int getWeight() {        return weight;    }    public void setWeight(int weight) {        this.weight = weight;    }}
public class DomesticCat extends Cat {    private String name;    public DomesticCat() {    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}
<hibernate-mapping package="Sample.Entity"><class name="Cat" table="CATS">    <id name="uid" column="UID">        <generator class="native"/>    </id>    <property name="birthday" type="date"/>    <property name="color"/>    <property name="sex"/>    <property name="weight"/>    <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">        <key column="CAT"/>        <property name="name" type="string"/>    </joined-subclass></class></hibernate-mapping>

这里写图片描述
映射到多张表中,但是子表并没有父表的属性,只有一个父表的外键.
优点:减少了数据冗余
缺点:数据量太大是,join操作会影响性能
4. Table per class
每个表一个映射表,注意:此时ID生成策略不能使用generate,需要手动保证子父表之间ID的唯一性,可以考虑使用generateTable方法.

    @Entity(name = "Account")@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)public static class Account {    @Id    private Long id;    private String owner;    private BigDecimal balance;    private BigDecimal interestRate;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getOwner() {        return owner;    }    public void setOwner(String owner) {        this.owner = owner;    }    public BigDecimal getBalance() {        return balance;    }    public void setBalance(BigDecimal balance) {        this.balance = balance;    }    public BigDecimal getInterestRate() {        return interestRate;    }    public void setInterestRate(BigDecimal interestRate) {        this.interestRate = interestRate;    }}@Entity(name = "DebitAccount")public static class DebitAccount extends Account {    private BigDecimal overdraftFee;    public BigDecimal getOverdraftFee() {        return overdraftFee;    }    public void setOverdraftFee(BigDecimal overdraftFee) {        this.overdraftFee = overdraftFee;    }}@Entity(name = "CreditAccount")public static class CreditAccount extends Account {    private BigDecimal creditLimit;    public BigDecimal getCreditLimit() {        return creditLimit;    }    public void setCreditLimit(BigDecimal creditLimit) {        this.creditLimit = creditLimit;    }}       
    CREATE TABLE Account (    id BIGINT NOT NULL ,    balance NUMERIC(19, 2) ,    interestRate NUMERIC(19, 2) ,    owner VARCHAR(255) ,    PRIMARY KEY ( id ))CREATE TABLE CreditAccount (    id BIGINT NOT NULL ,    balance NUMERIC(19, 2) ,    interestRate NUMERIC(19, 2) ,    owner VARCHAR(255) ,    creditLimit NUMERIC(19, 2) ,    PRIMARY KEY ( id ))CREATE TABLE DebitAccount (    id BIGINT NOT NULL ,    balance NUMERIC(19, 2) ,    interestRate NUMERIC(19, 2) ,    owner VARCHAR(255) ,    overdraftFee NUMERIC(19, 2) ,    PRIMARY KEY ( id ))

注意生成了三张表,对应三个类,并且每个类的主键都没有依赖,为了保证每个对象都是有唯一的id,(内存中三个对象id都需要不同)我们需要手动保证三个table的id列都是唯一的,比如说,Account中有一个元组中id为1,那么DebitAccount中就不能有元组id为1.同理,DebitAccount中有id为1,其他两个表也是一样.
查询的时候,三个表之间使用了union查询语句.
配置版本:

    public class Fruit {    private Long id;    private String shape;    private String flavor;    private String color;    public Fruit() {    }    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getShape() {        return shape;    }    public void setShape(String shape) {        this.shape = shape;    }    public String getFlavor() {        return flavor;    }    public void setFlavor(String flavor) {        this.flavor = flavor;    }    public String getColor() {        return color;    }    public void setColor(String color) {        this.color = color;    }}public class Banana extends Fruit{    private int length;    public Banana() {    }    public int getLength() {        return length;    }    public void setLength(int length) {        this.length = length;    }}public class Apple extends Fruit {    private int weight;    public Apple() {    }    public int getWeight() {        return weight;    }    public void setWeight(int weight) {        this.weight = weight;    }}
<hibernate-mapping package="entities">    <class name="entities.Fruit" table="`fruit`">        <id name="id" column="ID">            <!--table per class 策略不能使用 generate 策略,否则无法生成sessionFactory.可以考虑使用generateTable-->        </id>        <property name="shape"/>        <property name="flavor"/>        <property name="color"/>        <union-subclass name="Apple" table="`apple`">            <property name="weight"/>        </union-subclass>        <union-subclass name="entities.Banana" table="`banana`">            <property name="length"/>        </union-subclass>    </class></hibernate-mapping>

这里写图片描述

好了,至此,内存中的对象与数据库元组之间的继承关系和关联关系已经下完了.

贴上课上PPT

原创粉丝点击