Hibernate入門之注解@Column詳解


前言

上一節我們講解了Hibernate的主鍵生成策略,本節我們繼續來講講Hibernate中針對列的映射即@Column注解,文中若有錯誤之處,還望指正。

@Column注解詳解

我們看到如上針對列注解上所對應的屬性設置,主要有列名、唯一約束(默認為非)、可空(默認為空)、可插入(默認為true)、可更新(默認為true)、列定義(默認空字符串)、所屬表名(默認為空字符串)、長度(默認為255)、小數位數(默認為0)等,這里我們重點講解insertable、updatable、columnDefinition、precision屬性。

屬性insertable和updatable

首先我們給出如下兩個POJO對象,一個是國家、另外一個則是城市郵編,一個國家下有多個城市即對應多個郵編,而一個城市郵編則只屬於特定國家,所以國家和城市郵編是一對多的關系,后續講解關系映射時會進一步詳細講解,如下:@Entity

@Entity
public class Country {

    public Country() {
    }

    //國家編碼
    @Id
    @Column(length = 20)
    private String iso_code;

    //國家名稱
    @Column
    private String name;

    public void setIso_code(String iso_code) {
        this.iso_code = iso_code;
    }

    public String getIso_code() {
        return iso_code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(mappedBy = "country", cascade = CascadeType.ALL)
    private List<Zip> zips;

    public List<Zip> getZips() {
        return zips;
    }

    public void setZips(List<Zip> zips) {
        this.zips = zips;
    }
}

在上述國家對象中,我們以iso_code作為主鍵且值由我們顯式指定,在如下城市郵編對象中,我們顯式指定外鍵列名為country_code,同時呢,我們也以定義一個屬性為country_code作為主鍵,如下:

@Entity
public class Zip {

    //所屬國家編碼
    @Id
@Column(length = 20)
private String country_code; @ManyToOne @JoinColumn(name = "country_code") private Country country; //城市名稱 @Column private String city_name; //城市郵編 @Column private String code; public void setCountry_code(String country_code) { this.country_code = country_code; } public String getCountry_code() { return country_code; } public void setCity_name(String city_name) { this.city_name = city_name; } public String getCity_name() { return city_name; } public void setCode(String code) { this.code = code; } public String getCode() { return code; } }

接下來我們打開會話去保存country,如下:

Country country = new Country();
country.setName("中國");
country.setIso_code("CHI");

Zip zip = new Zip();
zip.setCity_name("深圳");
zip.setCode("518000");
zip.setCountry_code(country.getIso_code());
country.setZips(Arrays.asList(zip));

session.save(country);

此時將拋出如上異常錯誤,因為我們顯式指定外鍵列名為country_code,同時主鍵列名也為country_code,此時將映射為同一列,也就是說country_code屬於共享主鍵,但是針對指定的主鍵列country_code,我們可以顯式設定值,此時將引起外鍵列也為country_code即與country中的iso_code值不一致的問題,所以為了修正這種情況,Hibernate要求我們必須使用其中之一來進行插入、更新,而另外一個則將只讀,所以我們需要將外鍵列設置為不允許插入和更新,如下:

 

看到網上一些文章對於上述insertable和updatable的設置將其解釋為:可能我們會通過上述城市郵編對象(zip)來反向創建國家對象(country),因為zip並不負責創建和更新country,反之,我們只能通過country來創建和更新zip,其實沒有很大的說服力,這個說法我個人認為是錯誤的,我個人認為:insertable和updatable與相關實體的插入和更新無關,此二者屬性背后真正的意圖是防止列在當前實體的插入和更新,也就是說在實體中多次映射字段時(比如上述共享主鍵),這兩個屬性將很有用,可以進一步進行修正,常見的場景為:使用組合鍵、使用共享主鍵、使用級聯主鍵。

屬性columnDefinition

我們知道對於字符串默認為長度為255且可空,下面我們將country對象中的name屬性顯示設置其長度為120且不可空,如下:

 

如下,我們通過屬性columnDefinition來進一步設置其長度為100且不可空,此時映射到表中的列到底是可空還是不可空,長度到底是100還是120呢?

@Column(columnDefinition = "varchar(100) not null", length = 120)
private String name;

我們可以看到此時將以屬性columnDefinition定義的為准,也就是length將會被覆蓋,那是不是說明通過columnDefinition設置后都將會被覆蓋,事實真的如此嗎?

@Column(columnDefinition = "varchar(100) null", nullable = false, length = 120)
private String name;
create table Country (iso_code varchar(20) not null, name varchar(100) null not null, primary key (iso_code))

我們可以看到此時通過columnDefinition屬性上設置可空,但是通過nullable設置為不可空,最終映射到表中的列卻是不可空,這說明此時columnDefinition中的null被冗余。我們可以看到我們設置長度、可空、精度、唯一約束有兩種方式,其一可以通過對應屬性比如length、nullable、precision、unique設置,其二可以通過columnDefinition設置,那么為何Hibernate要同時提供這兩種方式呢?它的目的是什么呢?我認為提供這兩種方式說明了其靈活性,若是簡單的設置(比如只設置長度)則直接使用length即可,若需全部設置,則通過columnDefinition設置來的方便。數據庫DDL由:(name + columnDefinition)構成,它是物理的,即columnDefinition是生成列的DDL時使用的SQL片段,對於長度、精度、唯一約束使用columnDefinition將會被覆蓋,而對於null可能被覆蓋或冗余。

總結

本節我們詳細講解了列注解@Column上的屬性insertable和updatable以及columnDefinition的詳細使用,下一節我們講解枚舉注解,感謝您的閱讀,我們下節見。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM