前言

上一节我们讲解了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. python_数据类型_总结

  2. 46)PHP,PHP语言为啥需要服务器

    1)用户的 Web 浏览器发出 HTTP 请求,请求特定 Web 页面. 2)Web服务器收到.php 的请求获取该文件,并将它传到 PHP 引擎,要求它处理. 3)PHP 引擎开始解析脚本. 脚本中 ...

  3. Java接口和抽象类区别

    1.抽象类 [public] abstract class ClassName { abstract void fun(); } extends 包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有 ...

  4. SpringBoot开发二十-Redis入门以及Spring整合Redis

    安装 Redis,熟悉 Redis 的命令以及整合Redis,在Spring 中使用Redis. 代码实现 Redis 内置了 16 个库,索引是 0-15 ,默认选择第 0 个 Redis 的常用命 ...

  5. 手撸GBDT原理(未完成)

    一直对GBDT里面的具体计算逻辑不太清楚,在网上发现了一篇好博客. 先上总结的关系图 GBDT对类别变量是怎么处理的? 这些东西都是在网上发现的,讲的挺好的. GBDT原理与Sklearn源码分析-回 ...

  6. Web服务器的配置与管理

    Web服务器的配置与管理(2) 虚拟主机技术 在上篇博文中,我们已经利用IIS搭建好了一台Web服务器,并可以成功访问IIS中自带的默认站点,那么我们是否可以在这台服务器中再创建另外一个Web站点?也 ...

  7. 2015-09-14-初级string

    标准库string类型 string对象初始化 string s1; string s2(s1); string s3("value"); string s4(n,'c'); st ...

  8. 为何印度打车软件Ola,也难逃“资本合并”命运?

    从全球市场来看,共享经济已经引发了多场具有颠覆性的风暴.尤其是在与大众关系紧密的衣食住行方面,诞生了具有强势影响力的独角兽企业.如,共享打车企业Uber.共享房屋出租企业Airbnb等.而鉴于每个国家 ...

  9. UnitTest测试框架-操作步骤

    一.UnitTest 1. TestCase 说明:测试用例 1.新建类并集成unittest.TestCase 2. TestSuite 说明:测试套件(多条用例) 方法: 1. 实例化 suite ...

  10. Hibernate中的对象图关系转换:游离、持久、自由状态