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

  • 相关阅读:
    jQuery ajax传多个参数
    PHP 上传图片和安全处理
    PHP CI框架email类发送邮件
    2016-4-7
    jquery 轮播图
    CI控制器的继承问题
    2016-4-1
    2016-3-31 总结
    php内置函数call_user_func()
    discuz-目录
  • 原文地址:https://www.cnblogs.com/CreateMyself/p/12390886.html
Copyright © 2020-2023  润新知