prologue
JPA는 왜 쓰는 걸까요?
> Entity 변경에 따른 SQL문 수정 없이 코드 수정으로 DB종속성을 없앨 수 있다는 장점.. 그리고 dialect를 통한 DB 종류에 따른 쿼리문을 신경 쓰지 않아도 되는 점이 매력적이죠.
장점이 큰데 여전히 mybatis를 많이 쓸까요?
> 쿼리 자유도를 따져보면 직접 생성한 쿼리로 처리 가능한 경우도 많고 통계 같이 복잡한 쿼리문은 JPA로 처리하기 힘들 수 있어요. learning-curve가 있는 기술이며 기존 쿼리를 완벽하게 대체하기는 어렵습니다.
JPA가 편하고 훨씬 개발 속도가 빠른데 왜 mybatis 써요?
라고 하는 동료와 논쟁을 벌인 적이 있었습니다.
1. 레거시 프로젝트들이 대부분 mybatis라서 유지보수하는데 복잡해짐.
2. 회사에서 JPA를 다루는 사람이 없습니다. (님은 이직할거면서 왜..)
3. 통계같은 쿼리는 JPA로 안됨
4. 섞어 쓸 수 있지만 쿼리에 따라서 어느 기술을 쓸지 정해야 하는 판단하는 과정이 생김.
편하고 좋은 기술은 맞지만 유지보수할 사람이 없는 상황..(개발자 계속 바뀌는 회사)
(이런 기억이 있네요)
이 글에서는 단순히 코드로 JPA 세팅을 하는 내용을 남겨두려합니다.
JPA?
Java Persistence API의 약자로
JSR 220, 317, 338 에 명시되어 있습니다. 2007년(JSR 220)부터 준비하던 기술이라는 TMI를..
DB관점이 아닌 코드 관점에서 DB를 제어한다는 개념으로 사용하는 기술이라 생각하면 이해하기 쉬울까요?
실제로 코드에 따라 DDL이 변형됩니다.
다시 말하면 일반적인 개발에서는 DB가 변하면 그에 따라 코드를 수정해야 했다면(DB 변경이 코드에 영향),
JPA는 소스코드를 수정을 통해 DB를 변경합니다(코드 변경이 DB에 영향).
JPA 설정
JPA를 사용하기 위해서는 persistence.xml 이란 파일을 구성해 주어야 합니다.
패키지 형태가 EJB JAR의 경우에는 META-INF 디렉터리 내에 persistence.xml로
패키지 형태가 WAR인 경우에는 /WEB-INF/classes/META-INF 경로에 persistence.xml를 위치시켜 줍니다.
(나중에 필요하다면 추가)
하지만 저는 사파이기 때문에(?) 이걸 안 쓰고 코드로 구성할 생각입니다.
개발자마다 세팅은 다르게 하겠지만
JPA 세팅은 아래처럼 구성해 봤습니다.
@Configuration
@EnableJpaRepositories(basePackages = "com.lodean.**.dao", entityManagerFactoryRef = "entityManagerFactory" )
public class JpaConfig {
@Bean("entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Autowired DataSource dataSource, @Qualifier("jpaProperties") Properties jpaProperties) {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
vendorAdapter.setShowSql(true);
factoryBean.setDataSource(dataSource);
//factoryBean.setPersistenceUnitName("tester");
factoryBean.setJpaVendorAdapter(vendorAdapter);
factoryBean.setPackagesToScan("com.lodean.**.dao**");
//factoryBean.setPersistenceProviderClass((Class<? extends PersistenceProvider) SpringHibernateJpaPersistenceProvider.class);
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean;
}
@Bean("jpaProperties")
public Properties jpaProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update"); //세팅 중요.. 구조 바꾸면 테이블 다시
//properties.setProperty("hibernate.dialect", dialect);
properties.setProperty("hibernate.show_sql", "true");
return properties;
}
}
properties에서 중요한 점은 [hibernate.hbm2ddl.auto] 항목인데
아래 항목들을 사용할 수 있습니다.
create의 경우에는 애플리케이션 재구동시 유지되지 않으니 조심해야 합니다.
create
update
create-drop
validate
none
Entity 구성 및 결과
Entity구성은
테스트 삼아 key를 시퀀스로 갖는 경우와 2개 칼럼을 유니크로 쓰는 것을 테스트 해볼 예정입니다.
1. 2개의 컬럼을 유니크로 쓰는 경우
//unique로 2개의 컬럼 사용
@Entity
@IdClass(ItemPK.class) //ItemPK class는 unique로 사용할 컬럼으로 구성 및 @Id로 구분
@Table(name = "meta_item")
public class Item {
//@EmbeddedId ItemPK pk;
@Id
@Column(name = "com_id")
private String comId;
@Id
@Column(name = "item_name")
private String itemName;
@Column
private Timestamp creDate;
//... getter and setter
}
//ItemPK.java
public class ItemPK implements Serializable{
private String comId;
private String itemName;
//... getter and setter
}
1-1. Repository의 구성 예제
import org.springframework.data.repository.Repository;
@org.springframework.stereotype.Repository
public interface ItemRepository extends Repository<Item, ItemPK> { //Repository에 테이블 구조와 키 형태를 구분
Item save(Item item);
}
2. sequence를 생성 및 키 설정
@Entity
@SuppressWarnings("serial")
public class Test implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = true)
private String email;
//... getter and setter
}
2-1. Repository의 구성 예제
@org.springframework.stereotype.Repository
public interface TestRepository extends Repository<Test, Long> {
Page<Test> findAll(Pageable pageable);
Test save(Test entity);
}
3. uuid를 키 생성 및 키 설정
@Entity
@Table(name = "meta_mud")
public class ItemMud {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
@Column(name = "com_id")
private String comId;
@Column(name = "item_name")
private String itemName;
@Column
private Timestamp creDate;
}
3-1. Repository의 구성 예제
import org.springframework.data.repository.Repository;
@org.springframework.stereotype.Repository
public interface ItemMudRepository extends Repository<Item, String> {
Item save(Item item);
}
#앱 구동 시 나오는 ddl 참고
Hibernate: create table meta_mud (com_id varchar(255) not null, creDate datetime(6), item_name varchar(255), primary key (com_id)) engine=InnoDB
Hibernate: create table meta_item (com_id varchar(255) not null, item_name varchar(255) not null, creDate datetime(6), primary key (com_id, item_name)) engine=InnoDB
Hibernate: create table Test (id bigint not null, email varchar(255), name varchar(255) not null, primary key (id)) engine=InnoDB
Hibernate: create sequence Test_SEQ start with 1 increment by 50 nocache
epilogue
기회가 된다면 실제 프로젝트에 적용해 볼 예정이지만..
mybatis로 조작하는 게 더 편하지 않나 싶네요
'IT-개발 > JAVA' 카테고리의 다른 글
springboot - Embedded Tomcat Cache 조정하기 (0) | 2024.05.28 |
---|---|
java - Apache Ant 빌드 사용 (0) | 2024.05.14 |
java - 오래된 프로젝트의 Ant build 사용 (0) | 2023.04.24 |