前言

上一节我们讲解了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的详细使用,下一节我们讲解枚举注解,感谢您的阅读,我们下节见。

Hibernate入门之注解@Column详解的更多相关文章

  1. Hibernate配置文件和映射文件详解

    Hibernate是一个彻底的ORM(Object Relational Mapping,对象关系映射)开源框架. 我们先看一下官方文档所给出的,Hibernate 体系结构的高层视图: 其中PO=P ...

  2. 转:springmvc常用注解标签详解

    Spring5:@Autowired注解.@Resource注解和@Service注解 - IT·达人 - 博客园--这篇顺序渐进,讲得超级好--此人博客很不错http://www.cnblogs.c ...

  3. Java 注解用法详解——@SuppressWarnings

    转自: https://www.cnblogs.com/fsjohnhuang/p/4040785.html Java魔法堂:注解用法详解——@SuppressWarnings   一.前言 编码时我 ...

  4. Spring 入门 web.xml配置详解

    Spring 入门 web.xml配置详解 https://www.cnblogs.com/cczz_11/p/4363314.html https://blog.csdn.net/hellolove ...

  5. @SuppressWarnings注解用法详解

    @SuppressWarnings注解用法详解 今天来谈谈@SuppressWarnings注解的作用. J2SE 提供的最后一个批注是 @SuppressWarnings.该批注的作用是给编译器一条 ...

  6. 爬虫入门之urllib库详解(二)

    爬虫入门之urllib库详解(二) 1 urllib模块 urllib模块是一个运用于URL的包 urllib.request用于访问和读取URLS urllib.error包括了所有urllib.r ...

  7. 分享知识-快乐自己:Hibernate 中Criteria Query查询详解

    1):Hibernate 中Criteria Query查询详解 当查询数据时,人们往往需要设置查询条件.在SQL或HQL语句中,查询条件常常放在where子句中. 此外,Hibernate还支持Cr ...

  8. Spring 注解@Value详解

    一.spring(基础10) 注解@Value详解[1] 一 配置方式 @value需要参数,这里参数可以是两种形式: [html] view plain copy @Value("#{co ...

  9. 《挑战30天C++入门极限》入门教程:实例详解C++友元

        入门教程:实例详解C++友元 在说明什么是友元之前,我们先说明一下为什么需要友元与友元的缺点: 通常对于普通函数来说,要访问类的保护成员是不可能的,如果想这么做那么必须把类的成员都生命成为pu ...

随机推荐

  1. 30)PHP,引用对象和克隆对象的区别

    复制文件.建立快捷方式的区别,克隆就是复制,引用就是快捷方式,引用的对象实际上同一个东西,修改任何一个变量,另外一个也会跟着变化.

  2. 系统学习Javaweb9----BootStrap1

    学习内容: 1.BootStrap的简述 2.BootStrap环境搭建 3.BootStrap环境搭建-基本模板创建 4.BootStrap环境搭建-基本模板讲解 5.BootStrap布局容器 6 ...

  3. 005.前端开发知识,前端基础CSS(2020-01-14)

    一.CSS权重 权重是可以叠加的,事例如下: div ul li ------> 0,0,0,3 .nav ul li ------> 0,0,1,2 a:hover -----—> ...

  4. docker里修改时间

    在docker容器里,你会发现,你根本无法通过命令修改时间.这时我们就可以通过/etc/localtime这个配置文件修改时间了.但这个配置文件是一个二进制的文件,里面根本就是一堆乱码.所以我只好拷贝 ...

  5. ORs-1-introduction

    introduction: 1.Olfactory receptors (ORs)很重要 2.已知的ORs的分子结构,但仍存在没清楚的地方: Though the relationship betwe ...

  6. RadixSort(基数排序)原理及C++代码实现

    基数排序是一种思想很值得学习的排序方法. 它突破了正常的排序思维:先排高位,如果高位相同再排次高位,直至最低.它的思想是利用稳定排序从低位开始排,最后再排最高位. 另外它用来划分的位不一定是一位一位的 ...

  7. Codeforces Roundd #573 (Div. 2)

    D. Tokitsukaze, CSL and Stone Game 题意:有n堆石头,每人每次只能去一颗石子,若轮到当前人没任何一堆石子可以取或当前人取到后剩下有俩堆石子个数相同则当前人输: 给定石 ...

  8. C语言占位符(待完善)

    %c 读入一个字符 %s 读入一个字符串,遇到空格制表符或者换行符时结束. %d 读入一个十进制整数 %x或者%X   读入一个十六进制整数(读出时,%x:小写,%X:大写) %o   读入一个八进制 ...

  9. Google DevTools Explanation

    Evaluating network performance The Network panel records information about each network operation in ...

  10. Centos7下常见命令

    1:  hostnamectl set-hostname  oldgirl   设置主机名直接生效 2:  hostname oldboy   (暂时生效,重启后恢复原来主机名)