Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java at意味着以易于复制的方式存储_Java_Hibernate_Orm_Jpa_Annotations - Fatal编程技术网

Java at意味着以易于复制的方式存储

Java at意味着以易于复制的方式存储,java,hibernate,orm,jpa,annotations,Java,Hibernate,Orm,Jpa,Annotations,什么是封装?封装意味着用一个接口封装数据(或状态),应用程序/客户端可以使用该接口安全地访问数据——保持数据的一致性和有效性 把这个想象成Word女士。MS Word在内存中维护文档的模型—文档状态。它提供了一个用户可以用来修改文档的界面—一组按钮、工具、键盘命令等。但是,当您选择保存(保存)该文档时,它会保存内部状态,而不是用于生成该文档的一组按键和鼠标单击 保存对象的内部状态不会破坏封装——否则您就无法真正理解封装的含义以及它存在的原因。这实际上就像对象序列化一样 因此,在大多数情况下,保存

什么是封装?封装意味着用一个接口封装数据(或状态),应用程序/客户端可以使用该接口安全地访问数据——保持数据的一致性和有效性

把这个想象成Word女士。MS Word在内存中维护文档的模型—文档状态。它提供了一个用户可以用来修改文档的界面—一组按钮、工具、键盘命令等。但是,当您选择保存(保存)该文档时,它会保存内部状态,而不是用于生成该文档的一组按键和鼠标单击

保存对象的内部状态不会破坏封装——否则您就无法真正理解封装的含义以及它存在的原因。这实际上就像对象序列化一样

因此,在大多数情况下,保存字段而不是访问器是合适的。这意味着可以完全按照存储方式从数据库中准确地重新创建对象。它不需要任何验证,因为这是在原始数据创建时以及存储在数据库中之前完成的(除非,上帝禁止,您正在数据库中存储无效数据!!!!)。同样,不需要计算值,因为它们在存储对象之前已经计算过了。对象的外观应与保存前相同。事实上,通过在getter/setter中添加额外的内容,实际上增加了重新创建与原始内容不完全相同的内容的风险


当然,添加此功能是有原因的。可能存在一些持久化访问器的有效用例,但是,它们通常很少。例如,您可能希望避免持久化计算出的值,但您可能想问这样一个问题:为什么不在值的getter中按需计算它,或者在getter中懒洋洋地初始化它。就我个人而言,我想不出任何好的用例,这里没有一个答案能真正给出“软件工程”的答案

要使类更干净,请将注释放在字段中,然后使用@Access(AccessType.PROPERTY)

我喜欢字段访问器。代码要干净得多。所有注释都可以放在一个文件中 类的一部分,代码更易于阅读

我发现了属性访问器的另一个问题:如果类中的getXYZ方法没有注释为与持久属性关联,hibernate会生成sql来尝试获取这些属性,从而导致一些非常混乱的错误消息。浪费了两个小时。我没有写这个代码;我过去一直使用字段访问器,从未遇到过这个问题

此应用程序中使用的休眠版本:


3.3.2.GA
3.4.0.GA
3.1.0.GA
3.4.0.GA

我们创建了实体bean并使用了getter注释。我们遇到的问题是:一些实体对某些属性具有复杂的规则,这些规则与何时可以更新属性有关。解决方案是在每个setter中都有一些业务逻辑,用于确定实际值是否发生更改,如果发生更改,则确定是否允许更改。当然,Hibernate总是可以设置属性,所以我们最终得到了两组设置器。很难看

在阅读之前的文章时,我还发现从实体内部引用属性可能会导致集合未加载的问题


总之,我倾向于在将来对字段进行注释。

如果您想在setter中做更多的事情,而不仅仅是设置值(例如加密或计算),我强烈建议使用字段访问,而不是在getter上进行注释(属性访问)

属性访问的问题是,在加载对象时也会调用setter。在我们想要引入加密技术之前,这对我来说已经有好几个月的时间了。在我们的用例中,我们希望在setter中加密一个字段,并在getter中解密它。 现在属性访问的问题是,当Hibernate加载对象时,它也在调用setter来填充字段,从而再次加密加密的值。 这篇文章还提到:


这让我头疼,直到我记起字段访问和属性访问之间的区别。现在,我已将所有注释从属性访问移到字段访问,现在一切正常

支持字段访问的另一点是,否则您将被迫公开集合的setter,这对我来说是个坏主意,因为将持久集合实例更改为非Hibernate管理的对象肯定会破坏您的数据一致性


因此,我更喜欢将集合作为受保护的字段初始化为默认构造函数中的空实现,并且只公开它们的getter。然后,只有像
clear()
remove()
removeAll()
等托管操作才可能使Hibernate永远不会不知道更改。

我更喜欢字段,但我遇到了一种情况,似乎迫使我将注释放在getter上


在Hibernate JPA实现中,
@Embedded
似乎无法在字段上工作。因此,这必须继续下去。一旦你把它放在getter上,那么各种
@Column
注释也必须放在getter上。(我认为Hibernate不希望在这里混合使用字段和getter。)并且,一旦您将
@Column
放在一个类中的getter上,那么在整个过程中这样做可能是有意义的。

我更喜欢使用字段访问,原因如下:

  • 在实现equals/hashCode和时,属性访问可能会导致非常严重的错误(而不是通过它们的getter)。这是因为代理仅在访问getter时初始化,而直接字段访问只会返回null

  • 属性访问要求您
    @Test
    public void testFieldBean() {
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        FieldBean fb = new FieldBean("field");
        Long id = (Long) session.save(fb);
        tx.commit();
        session.close();
    
        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        fb = (FieldBean) session.load(FieldBean.class, id);
        System.out.println(fb.getId());
        tx.commit();
        session.close();
    }
    
    @Test
    public void testPropBean() {
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        PropBean pb = new PropBean("prop");
        Long id = (Long) session.save(pb);
        tx.commit();
        session.close();
    
        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        pb = (PropBean) session.load(PropBean.class, id);
        System.out.println(pb.getId());
        tx.commit();
        session.close();
    }
    
    @Entity
    public class Person {
    
      @Column("nickName")
      public String getNickName(){
         if(this.name != null) return generateFunnyNick(this.name);
         else return "John Doe";
      }
    }
    
    public abstract class Foo<T extends Bar> {
    
        T oneThing;
        T anotherThing;
    
        // getters and setters ommited for brevity
    
        // Lots and lots of implementation regarding oneThing and anotherThing here
     }
    
    @Entity
    @Access(AccessType.FIELD)
    public class SomeEntity implements Serializable
    {
    ...
    }