Hibernate VS JPA

Hibetnate JPA
Entity와 Value-type 개념은 rich and fine-grained domain model을 지원하기 위한 필수 요소다. Value-type을 embeddable classes 라고 부른다. nonportable.
10가지나 되는 식별자 생성기 제공한다. 4가지만 지원한다. 벤더가 확장할 수 있도록 지원한다.
필드, Accessor 메소드, PropertyAccessor 인터페이스 구현체를 통해서 접근 가능하다. 혼용할 수 있다. 속성이나, Accessor 메소드로 접근할 수 있는데, 하이버네이트 애노테이션 없이 혼용할 수는 없다.
formula와 DB가 생성한 값을 사용할 수 있다. JPA에는 이런 거 없다. 하이버가 필요하다.

Hibernate Core와 Java Persistence and EJB 3.0

Hibernate Core Java Persistence and EJB 3.0
Persistence 클래스는 프록시 기반의 Lazy Loading을 사용할 때에만 아규먼트가 없는 public 또는 protected의 생성자를 필요로 한다. JPA는 모든 Entity 클래스들이 반드시 아규먼트가 없는 public 또는 protected의 생성자를 가지고 있어야만 한다.
Persistent 콜렉션은 반드시 인터페이스 타입이어야 하며, JDK가 제공하는 모든 인터페이스를 지원한다. 마찬가지로 모두 인터페이스 타입이어야 하며, 정렬된 콜렉션을 제외한 일부 인터페이스만 완전히 이식가능한 형태로 사용할 수 있다.
Persistent 속성들은 실행시에 accessor나 필드를 통해서 접근할 수 있으며, 혹은 완전히 다른 전략을 적용할 수도 있다. 마찬가지로 accessor나 필드를 통해서 접근가능하지만, 이식성이 필수라면 두 방법 모두 그렇치 않다.
XML 메타데이터 형식으로 모든 하이버네이트 맵핑 옵션을 사용할 수 있다. JPA 애노테이션은 기본적이고 가장 발전된 형태의 맵핑 옵션을 모두 제공한다. 하이버네이트 애노테이션은 별도의 맵핑과 튜닝을 필요로 한다.
XML 맵핑 메타데이터는 전역적으로 설정될 수 있으며 XML placeholder를 사용해서 메타데이터를 독립적으로 유지할 수 있다. 전역적인 메타데이터는 org.xml 메타데이터 파일에 두어야 이식성을 유지할 수 있다.

컴포넌트 맵핑하기

특징

  • 자바 객체에서 Value-type과 Entity를 구분지을 수 있는것은 식별자 속성 뿐이다.
  • 컴포넌트와 Entity 간의 양방향 관계를 설정할 수 있다.
  • 컴포넌트가 다른 컴포넌트나 Entity를 가지고 있을 수 있다.
    • This flexibility is the foundation of Hibernate’s support for finegrained object models.

설정하기

  • 컴포넌트에는 @Embeddable Entity의 속성에는 @Embedded 사용하기
  • @org.hibernate.annotations.Parent 애노테이션으로 컴포넌트에서 back-pointer 프로퍼티 사용 가능.
  • if you store a component object with all null property
    values, Hibernate returns a null component when the owning entity
    object is retrieved from the database.
컴포넌트 사용하기
@Entity
@Table(name = "USERS")
public class User {
@Embedded
private Address homeAddress;


}
컴포넌트 클래스 정의하기
@Embeddable
public class Address {

@Column(name="ADDRESS_STREET", nullable=false)
private String street;

@Column(name="ADDRESS_ZIPCODE", nullable=false)
private String zipcode;

@Column(name="ADDRESS_CITY", nullable=false)
private String city;

}
  • 컴포넌트를 사용하는 쪽에서 컴포넌트의 컬럼 정의를 재정의 할 수도 있다.
  • 단점
    • First,shared references, as for all value types, aren’t possible. -> 이건 value-type 이니까 당연히 그래야 하는거 아닌가.
    • Second, there is no elegant way to represent a null reference to an Address. -> 흠.. new Address()를 항상 가지고 있어야겠군.

기본 속성 맵핑하기

특징

  • @Transient 애노테이션을 붙이거나 자바의 transient 키워드를 사용하지 않으면 기본으로 전부 Persistent 대상으로 인식한다.
  • 애노테이션을 붙이지 않으면 다음과 같은 규칙이 적용된다.
    • JDK가 제공하는 타입일 경우에 자동으로 Persistent 대상이 된다.
    • 그렇지 않고, 속성의 타입에 해당하는 클래스에 @Embeddable 애노테이션이 붙어있는 경우, 컴포넌트를 가지고 있는 형태로 맵핑된다.
    • 그렇지도 않고, 속성의 타입이 Serializable 인터페이스를 구현한 경우, 직렬화된 형태로 DB에 저장된다. (이러길 원치 않을 것이다.)

설정하기

  • Chapter 17에서 하이버네이트 애노테이션으로 DDL을 작성하거나 동적으로 검증하는 기능에 대해 다룬다.
  • 클래스 속성에 접근하는 방법은 @Id 애노테이션이 붙어있는 위치가 기본 방법으로 설정 된다.(JPA)
  • 하이버네이트는 이 기본 방법을 변경할 수 있는 기능을 제공한다. @org.hibernate.annotations.AccessType(<strategy>)
    • 클래스에 AccessType 애노테이션을 사용하면, @Id로 인해 설정되는 접근 전략을 무시하며, 해당 클래스의 필드나 메서드에 붙어있는 모든 애노테이션들은 AccessType에서 정의한 접근 전략을 따른다.
    • 기본 상태이거나 필드 접근인 상태에서 @AccessType(“property”)를 필드 위에 붙여주면, 해당 속성을 accessor 메소드들을 이용해서 접근한다.
    • 기본 상태이거나 Accessor 접근이 상태에서 @AccessType(“field”)를 getter 위에 붙여주면, 해당 속성은 필드에 바로 접근한다.
    • @Embedded 클래스는 자신을 가지고 있는 쪽 클래스의 접근 방법을 따른다.
    • @MappedSuperclass 클래스는 맵핑 된 클래스의 접근 방법을 따른다.
  • noop 방식: “virtual” property in HQL queries. to use the database column in HQL queries only.
  • 마음에 드는게 없으면 org.hibernate.property.PropertyAccessor 인터페이스 구현해서 직접 만들어 됨.
    • 사용할 때는 @AccessType 애노테이션의 access 속성에 패키지 이름을 붙인 클래스 이름을 써주면 돼.

계산이 필요한 속성

  • 맵핑되는 컬럼은 없다.
  • @Fomula 애노테이션 사용하기
필드에서 계산된 속성 사용하기
@org.hibernate.annotations.Formula("TOTAL + TAX_RATE * TOTAL")
public BigDecimal getTotalIncludingTax() {
return totalIncludingTax;
}
  • SQL 함수도 사용할 수 있다.

h1, DB에서 생성된 값과 기본 값

  • public 세터를 만들지 말아라.
  • @Generated 애노테이션 사용하기
DB에서 생성된 값 사용하기
@Column(updatable = false, insertable = false)
@org.hibernate.annotations.Generated(
org.hibernate.annotations.GenerationTime.ALWAYS
)
private Date lastModified;
  • 기본값이 설정되도록 하려면 flush 해야한다.
  • columnDefinition 속성으로 기본값 설정하기
기본값 설정하기
@Column(name = "INITIAL_PRICE",
columnDefinition = "number(10,2) default '1'")
@org.hibernate.annotations.Generated(
org.hibernate.annotations.GenerationTime.INSERT
)
private BigDecimal initalPrice;
  • columnDefinition: complete properties for the column DDL, with datatype and all constraints.
    • DDL customization은 8장에서 다룬다.

모르는 것

  • @MappedSuperclass는 뭔가?

작명 지침 사용하기

특징

  • Hibernate provides a feature that allows you to enforce naming standards automatically.

설정하기

  • NamingStrategy 인터페이스 구현하기
  • ImprovedNamingStrategy 클래스 상속받아서 구현하기
네임스페이스 등록하기
import org.hibernate.cfg.ImprovedNamingStrategy;
import org.hibernate.util.StringHelper;

public class CENamingStrategy extends ImprovedNamingStrategy {
public String classToTableName(String className) {
return StringHelper.unqualify(className);
}

public String propertyToColumnName(String propertyName) {
return propertyName;
}

public String tableName(String tableName) {
return "CE_" + tableName;
}

public String columnName(String columnName) {
return columnName;
}

public String propertyToTableName(String className, String propertyName) {
return "CE_" + classToTableName(className) + '_'
+ propertyToColumnName(propertyName);
}
}
  • classToTableName(): <class> 맵핑에서 table 속성에 값을 입력하지 않았을 때 호출.
  • propertyToColumnName(): 명시적인 column 이름을 설정하지 않았을 때 호출.
  • tableName(), columnName(): 명시적으로 이름을 설정했을 때 호출.
  • 동적으로 설정을 바꿀 수 있음.
동적으로 네임스페이스 바꾸기
Configuration cfg = new Configuration();
cfg.setNamingStrategy( new CENamingStrategy() );
SessionFactory sessionFactory sf =
cfg.configure().buildSessionFactory();

모르는 것

  • SessionFactory 설정할 때 구현한 클래스를 등록해 주면 되는건가?