IT

최대 절전 모드 주석-필드 또는 속성 액세스 중 어떤 것이 더 좋습니까?

lottoking 2020. 7. 3. 18:05
반응형

최대 절전 모드 주석-필드 또는 속성 액세스 중 어떤 것이 더 좋습니까?


이 질문은 Hibernate Annotation Placement Question 과 다소 관련이 있습니다.

그러나 나는 어느 것이 좋은지 알고 싶습니다 . 속성을 통한 액세스 또는 필드를 통한 액세스? 각각의 장단점은 무엇입니까?


필요할 때마다 접근 자에 비즈니스 로직을 추가 할 수 있기 때문에 접근자를 선호합니다. 예를 들면 다음과 같습니다.

@Entity
public class Person {

  @Column("nickName")
  public String getNickName(){
     if(this.name != null) return generateFunnyNick(this.name);
     else return "John Doe";
  }
}

또한 다른 JSON을 믹스에 던지면 (예 : JSON 변환 lib 또는 BeanMapper 또는 Dozer 또는 getter / setter 속성을 기반으로하는 다른 bean 매핑 / 복제 라이브러리와 같이) lib가 지속성과 동기화되어 있음을 보장합니다 관리자 (둘 다 getter / setter 사용).


두 가지 모두에 대한 논거가 있지만 대부분의 사용자 요구 사항은 "논리를 추가해야하는 경우"또는 "xxxx가 캡슐화를 중단합니다"라는 특정 사용자 요구 사항에서 비롯됩니다. 그러나 아무도 이론에 대해 실제로 의견을 말하지 않았으며 합리적으로 합리적인 주장을 제시했습니다.

Hibernate / JPA는 객체를 유지할 때 실제로하는 일-객체의 상태를 유지합니다. 즉, 쉽게 재현 할 수있는 방식으로 보관해야합니다.

캡슐화 란 무엇입니까? 캡슐화 란 응용 프로그램 / 클라이언트가 데이터에 안전하게 액세스하는 데 사용할 수있는 인터페이스로 데이터 (또는 상태)를 캡슐화하여 일관성 있고 유효하게 유지하는 것을 의미합니다.

이것을 MS Word와 같이 생각하십시오. MS Word는 문서 모델을 메모리에 저장합니다 (문서 상태). 버튼, 도구, 키보드 명령 등 사용자가 문서를 수정하는 데 사용할 수있는 인터페이스를 제공합니다. 그러나 해당 문서를 유지 (저장)하도록 선택하면 키 누르기 세트가 아닌 내부 상태가 저장됩니다. 마우스 클릭으로 생성됩니다.

객체의 내부 상태를 저장하면 캡슐화가 중단되지 않습니다. 그렇지 않으면 캡슐화의 의미와 그 이유를 실제로 이해하지 못합니다. 그것은 실제로 객체 직렬화와 같습니다.

이러한 이유로, 대부분의 경우, 액세서가 아닌 필드를 유지하는 것이 적절합니다. 이는 객체가 저장된 방식대로 데이터베이스에서 객체를 정확하게 재생성 할 수 있음을 의미합니다. 원본을 만들 때와 데이터베이스에 저장하기 전에 원본에서 수행되었으므로 유효성 검사가 필요하지 않습니다 (하나님이 금지하지 않는 한 DB에 잘못된 데이터를 저장하고 있습니다 !!!!). 마찬가지로, 객체가 저장되기 전에 이미 계산되었으므로 값을 계산할 필요가 없습니다. 오브젝트는 오브젝트가 저장되기 전에 수행 된 방식대로 보여야합니다. 실제로 게터 / 세터에 추가 항목을 추가하면 실제로 원본의 정확한 사본이 아닌 것을 다시 만들 위험이 높아 집니다.

물론이 기능은 이유로 추가되었습니다. 접근자를 유지하기위한 유효한 사용 사례가있을 수 있지만 일반적으로 드물게 나타납니다. 예를 들어 계산 된 값을 유지하지 않으려는 경우가 있지만 값의 getter에서 요청시 값을 계산하지 않는 이유를 질문하거나 게터에서 게으르게 초기화하는 것이 좋습니다. 개인적으로 나는 어떤 유스 케이스도 생각할 수 없으며, 여기에 대한 답변 중 "소프트웨어 엔지니어링"답변은 없습니다.


각 속성에 대해 getter / setter를 제공하지 않아도되므로 필드 액세스를 선호합니다.

Google을 통한 빠른 설문 조사에 따르면 필드 액세스가 대부분 (예 : http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype )이라고합니다.

필드 액세스는 Spring에서 권장하는 관용구라고 생각하지만 백업을위한 참조를 찾을 수 없습니다.

성능을 측정하려고 시도하고 "차이가 없다"는 결론에 도달 관련 SO 질문 이 있습니다.


속성 접근자를 사용하는 상황이 있습니다. 8 개의 구체적인 서브 클래스로 상속 할 수있는 구현 성이 많은 GENERIC 추상 클래스가 있다고 상상해보십시오.

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
 }

이제이 클래스에 어떻게 주석을 달아야합니까? 답은이 시점에서 대상 엔터티를 지정할 수 없으므로 필드 또는 속성 액세스로 주석을 달 수 없습니다. 구체적인 구현에 주석을 달아야합니다. 그러나 지속 속성이이 슈퍼 클래스에 선언되어 있으므로 서브 클래스에서 속성 액세스를 사용해야합니다.

필드 액세스는 추상 일반 슈퍼 클래스가있는 응용 프로그램의 옵션이 아닙니다.


나는 속성 접근자를 선호하고 사용하는 경향이 있습니다.

  • 필요한 경우 (허용 된 답변에 언급 된대로) 논리를 추가 할 수 있습니다.
  • foo.getId() 프록시를 초기화하지 않고 전화를 걸 수 있습니다 ( HHH-3718 이 해결 될 때까지 최대 절전 모드를 사용할 때 중요합니다 ).

약점:

  • 코드를 읽기 쉽도록 만듭니다. 예를 들어, 전체 클래스를 탐색하여 @Transient주변에 있는지 확인해야합니다.

실제로는 특정한 경우에 따라 다릅니다. 두 가지 옵션을 모두 사용할 수 있습니다. IMO는 세 가지 사례로 요약됩니다.

  1. setter에는 데이터베이스에서 인스턴스를로드 할 때 실행해서는 안되는 몇 가지 논리가 있습니다. 예를 들어, 일부 값 유효성 검사는 setter에서 발생하지만 db에서 오는 데이터는 유효해야합니다 (그렇지 않으면 도달하지 못함 (:)).이 경우 필드 액세스가 가장 적합합니다.
  2. setter에는 db에서 인스턴스를로드하는 동안에도 항상 호출해야하는 로직이 있습니다. 예를 들어, 초기화되는 속성은 계산 된 일부 필드의 계산에 사용됩니다 (예 : 속성-화폐 금액, 계산 된 속성-동일한 인스턴스의 총 여러 통화 속성). 이 경우 속성 액세스가 필요합니다.
  3. 위의 경우 중 어느 것도 해당되지 않습니다-두 옵션 모두 적용 가능합니다. 일관성을 유지하십시오 (이 상황에서 필드 액세스가 선택되면 비슷한 상황에서 항상 사용하십시오).

값을 설정하는 것 (예 : 암호화 또는 계산)보다 세터에서 더 많은 작업을 수행하려는 경우 게터에 대한 필드 액세스 및 주석 주석 (속성 액세스)을 강력히 권장합니다.

속성 액세스의 문제점은 객체가로드 될 때 setter도 호출된다는 것입니다. 이것은 우리가 암호화를 도입하고 싶을 때까지 몇 달 동안 나에게 잘 작동했습니다. 우리의 유스 케이스에서는 setter에서 필드를 암호화하고 getter에서 필드를 해독하려고했습니다. 속성 액세스의 문제는 Hibernate가 객체를로드 할 때 필드를 채우기 위해 setter를 호출하여 암호화 된 값을 다시 암호화한다는 것입니다. 이 게시물은 또한 이것을 언급합니다 : Java Hibernate : 그것을 호출하는 사람에 따라 다른 속성 세트 함수 동작

필드 액세스와 속성 액세스의 차이점을 기억하기 전까지는 두통이 발생했습니다. 이제 모든 주석을 속성 액세스에서 필드 액세스로 옮겼으며 이제 제대로 작동합니다.


다음과 같은 이유로 필드 액세스를 선호합니다.

  1. 속성 액세스가 같음 / 해시 코드를 구현할 때 매우 불쾌한 버그로 이어질 수 직접적으로 필드를 참조 (자신의 게터를 통해 반대). 프록시가 게터에 액세스 할 때만 초기화되기 때문에 직접 필드 액세스는 단순히 null을 반환하기 때문입니다.

  2. 속성 액세스는 모든 주석을하도록 요구 유틸리티 메소드 등 (예하는 AddChild /로 removeChild) @Transient.

  3. 필드 액세스를 통해 게터를 전혀 노출시키지 않으면 서 @Version 필드를 숨길 수 있습니다. 게터는 또한 세터를 추가 할 수 있으며 version필드를 수동으로 설정해서는 안됩니다 (매우 불쾌한 문제가 발생할 수 있음). 모든 버전 증분은 OPTIMISTIC_FORCE_INCREMENT 또는 PESSIMISTIC_FORCE_INCREMENT 명시 적 잠금을 통해 트리거되어야합니다 .


ORM이 수행하는 경우에도 필드를 업데이트하면 캡슐화가 직접 중단되므로 속성에 주석을 추가하는 것이 좋습니다.

다음은 어디에서 화상을 입는 지에 대한 좋은 예입니다. 같은 위치 (필드 또는 속성)에서 최대 절전 모드 유효성 검사기 및 지속성을위한 주석을 원할 것입니다. 필드에 주석이 달린 최대 절전 모드 유효성 검사기 유효성 검사를 테스트하려는 경우 엔터티 모의를 사용하여 단위 테스트를 유효성 검사기 만 분리 할 수 ​​없습니다. 아야.


부동산 접근과 현장 접근은 게으른 초기화와 관련하여 미묘하게 다르다고 생각합니다.

2 개의 기본 Bean에 대해 다음 맵핑을 고려하십시오.

<hibernate-mapping package="org.nkl.model" default-access="field">
  <class name="FieldBean" table="FIELD_BEAN">
    <id name="id">
      <generator class="sequence" />
    </id>
    <property name="message" />
  </class>
</hibernate-mapping>

<hibernate-mapping package="org.nkl.model" default-access="property">
  <class name="PropBean" table="PROP_BEAN">
    <id name="id">
      <generator class="sequence" />
    </id>
    <property name="message" />
  </class>
</hibernate-mapping>

그리고 다음 단위 테스트 :

@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();
}

필요한 선택에 미묘한 차이가 있습니다.

Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        FIELD_BEAN
        (message, id) 
    values
        (?, ?)
Hibernate: 
    select
        fieldbean0_.id as id1_0_,
        fieldbean0_.message as message1_0_ 
    from
        FIELD_BEAN fieldbean0_ 
    where
        fieldbean0_.id=?
0
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        PROP_BEAN
        (message, id) 
    values
        (?, ?)
1

즉, 호출 fb.getId()에는 선택이 필요하지만 pb.getId()그렇지는 않습니다.


우리는 아직있다

That's an old presentation but Rod suggests that annotation on property access encourages anemic domain models and should not be the "default" way to annotate.


Another point in favor of field access is that otherwise you are forced to expose setters for collections as well what, for me, is a bad idea as changing the persistent collection instance to an object not managed by Hibernate will definitely break your data consistency.

So I prefer having collections as protected fields initialized to empty implementations in the default constructor and expose only their getters. Then, only managed operations like clear(), remove(), removeAll() etc are possible that will never make Hibernate unaware of changes.


I prefer fields, but I've run into one situation that seems to force me to place the annotations on getters.

With the Hibernate JPA implementation, @Embedded doesn't seem to work on fields. So that has to go on the getter. And once you put that on the getter, then the various @Column annotations have to go on the getters too. (I think Hibernate doesn't want mixing fields and getters here.) And once you're putting @Column on getters in one class, it probably makes sense to do that throughout.


I favor field accessors. The code is much cleaner. All the annotations can be placed in one section of a class and the code is much easier to read.

I found another problem with property accessors: if you have getXYZ methods on your class that are NOT annotated as being associated with persistent properties, hibernate generates sql to attempt to get those properties, resulting in some very confusing error messages. Two hours wasted. I did not write this code; I have always used field accessors in the past and have never run into this issue.

Hibernate versions used in this app:

<!-- hibernate -->
<hibernate-core.version>3.3.2.GA</hibernate-core.version>
<hibernate-annotations.version>3.4.0.GA</hibernate-annotations.version>
<hibernate-commons-annotations.version>3.1.0.GA</hibernate-commons-annotations.version>
<hibernate-entitymanager.version>3.4.0.GA</hibernate-entitymanager.version>

By default, JPA providers access the values of entity fields and map those fields to database columns using the entity’s JavaBean property accessor (getter) and mutator (setter) methods. As such, the names and types of the private fields in an entity do not matter to JPA. Instead, JPA looks at only the names and return types of the JavaBean property accessors. You can alter this using the @javax.persistence.Access annotation, which enables you to explicitly specify the access methodology that the JPA provider should employ.

@Entity
@Access(AccessType.FIELD)
public class SomeEntity implements Serializable
{
...
}

The available options for the AccessType enum are PROPERTY (the default) and FIELD. With PROPERTY, the provider gets and sets field values using the JavaBean property methods. FIELD makes the provider get and set field values using the instance fields. As a best practice, you should just stick to the default and use JavaBean properties unless you have a compelling reason to do otherwise.

You can put these property annotations on either the private fields or the public accessor methods. If you use AccessType.PROPERTY (default) and annotate the private fields instead of the JavaBean accessors, the field names must match the JavaBean property names. However, the names do not have to match if you annotate the JavaBean accessors. Likewise, if you use AccessType.FIELD and annotate the JavaBean accessors instead of the fields, the field names must also match the JavaBean property names. In this case, they do not have to match if you annotate the fields. It’s best to just be consistent and annotate the JavaBean accessors for AccessType.PROPERTY and the fields for AccessType.FIELD.

It is important that you should never mix JPA property annotations and JPA field annotations in the same entity. Doing so results in unspecified behavior and is very likely to cause errors.


Let me try to summarize the most important reasons for choosing field-based access. If you want to dive deeper, please read this article on my blog: Access Strategies in JPA and Hibernate – Which is better, field or property access?

Field-based access is by far the better option. Here are 5 reasons for it:

Reason 1: Better readability of your code

If you use field-based access, you annotate your entity attributes with your mapping annotations. By placing the definition of all entity attributes at the top of your class, you get a relatively compact view of all attributes and their mappings.

Reason 2: Omit getter or setter methods that shouldn’t be called by your application

Another advantage of field-based access is that your persistence provider, e.g., Hibernate or EclipseLink, doesn’t use the getter and setter methods of your entity attributes. That means that you don’t need to provide any method that shouldn’t be used by your business code. This is most often the case for setter methods of generated primary key attributes or version columns. Your persistence provider manages the values of these attributes, and you should not set them programmatically.

Reason 3: Flexible implementation of getter and setter methods

Because your persistence provider doesn’t call the getter and setter methods, they are not forced to fulfill any external requirements. You can implement these methods in any way you want. That enables you to implement business-specific validation rules, to trigger additional business logic or to convert the entity attribute into a different data type.

You can, for example, use that to wrap an optional association or attribute into a Java Optional.

Reason 4: No need to mark utility methods as @Transient

Another benefit of the field-based access strategy is that you don’t need to annotate your utility methods with @Transient. This annotation tells your persistence provider that a method or attribute is not part of the entity persistent state. And because with field-type access the persistent state gets defined by the attributes of your entity, your JPA implementation ignores all methods of your entity.

Reason 5: Avoid bugs when working with proxies

Hibernate uses proxies for lazily fetched to-one associations so that it can control the initialization of these associations. That approach works fine in almost all situations. But it introduces a dangerous pitfall if you use property-based access.

If you use property-based access, Hibernate initializes the attributes of the proxy object when you call the getter method. That’s always the case if you use the proxy object in your business code. But quite a lot of equals and hashCode implementations access the attributes directly. If this is the first time you access any of the proxy attributes, these attributes are still uninitialized.


You should choose access via fields over access via properties. With fields you can limit the data sent and received. With via properties you can send more data as a host, and set G denominations (which factory set most of the properties in total).


I had the same question regarding accesstype in hibernate and found some answers here.


I have solved lazy initialisation and field access here Hibernate one-to-one: getId() without fetching entire object


We created entity beans and used getter annotations. The problem we ran into is this: some entities have complex rules for some properties regarding when they can be updated. The solution was to have some business logic in each setter that determines whether or not the actual value changed and, if so, whether the change should be allowed. Of course, Hibernate can always set the properties, so we ended up with two groups of setters. Pretty ugly.

Reading previous posts, I also see that referencing the properties from inside the entity could lead to issues with collections not loading.

Bottom line, I would lean toward annotating the fields in the future.


Normally beans are POJO, so they have accessors anyway.

So the question is not "which one is better?", but simply "when to use field access?". And the answer is "when you don't need a setter/getter for the field!".


i thinking about this and i choose method accesor

why?

because field and methos accesor is the same but if later i need some logic in load field, i save move all annotation placed in fields

regards

Grubhart


To make your classes cleaner, put the annotation in the field then use @Access(AccessType.PROPERTY)


Both :

The EJB3 spec requires that you declare annotations on the element type that will be accessed, i.e. the getter method if you use property access, the field if you use field access.

https://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-mapping


AccessType.PROPERTY: The EJB persistence implementation will load state into your class via JavaBean "setter" methods, and retrieve state from your class using JavaBean "getter" methods. This is the default.

AccessType.FIELD: State is loaded and retrieved directly from your class' fields. You do not have to write JavaBean "getters" and "setters".

참고URL : https://stackoverflow.com/questions/594597/hibernate-annotations-which-is-better-field-or-property-access

반응형