Java에서 데이터베이스를 다루기 위한 표준 ORM 기술임 => RBD와 자바 객체간의 매핑을 지원해서 데이터베이스에 저장된 정보를 객체지향적으로 다룰 수 있게 도와줌
JPA를 구현한 프레임워크로는 Hibernate, EclipseLink, OpenJPA 존재함 => 여기서 Hibernate를 사용했음.
JDBC는 데이터베이스와 자바 애플리케이션 사이에서 중간 계층 역할을 수행하여 데이터베이스 관련 작업을 추상화하고 표준화함 => DB에 상관없이 표준화된 코드로 데이터베이스에 접근가능함.
JDBC를 사용하면 데이터베이스와의 접속, SQL 쿼리 실행, 결과 처리 등의 작업을 자바 코드로 처리할 수 있음.
JDBC는 인터페이스고, 구현한 것은 각 데이터베이스에 맞는 드라이버들임.
JPA는 데이터베이스와 객체를 매핑하는 기술일 뿐, 내부적으로는 데이터베이스와의 통신을 위해 JDBC를 사용한다.
또한 JPA도 JDBC와 마찬가지로 인터페이스이기 때문에 구현체가 필요하고, 그 구현체 중 하나가 Hibernate(가장 널리 사용됨)인 것.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.4'
}
spring.datasource.url=jdbc:mariadb://localhost:[설정포트]/[db이름]
spring.datasource.username=[설정유저네임]
spring.datasource.password=[비번]
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
여기서 spring.jpa.hibernate.ddl-auto=update 옵션은 ‘JPA 엔티티 설계’와 ‘실제 테이블 상태’를 비교하여, 차이점이 있다면 그것을 테이블에 반영하는 옵션이다.
칼럼삭제의 경우 테이블의 칼럼이 엔티티에 존재하지 않아도 삭제되지 않음.
ddl option 종류
create: 기존테이블 삭제 후 다시 생성 (DROP + CREATE)
create-drop: create와 같으나 종료시점에 테이블 DROP
update: 변경분만 반영(운영DB에서는 사용하면 안됨)
validate: 엔티티와 테이블이 정상 매핑되었는지만 확인
none: 사용하지 않음(사실상 없는 값이지만 관례상 none이라고 한다.)
Entity란 DB테이블에 대응하는 클래스이다.
@SqlResultMapping 어노테이션은 => createNativeQuery에서 sql쿼리문을 통해 Entity가 아닌 DTO로 직접 매핑하기 위해서 사용하는 어노테이션이다.
@Column 어노테이션으로 길이와 이름을 지정 할 수 있다.
기본적으로 Entity는 camelCase로 작성하고, 이것은 DB에서 snake_case로 매핑된다.(이렇게 작성하는 것이 기본 규칙)
다른 방식으로 매핑을 해주려면 @Column 어노테이션의 name 값을 직접 지정해줘야 한다.
import javax.persistence.*;
import java.math.BigInteger;
import java.sql.Date;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "exampleEntitiy")
@SqlResultSetMapping(
name = "contractDTOMapping",
classes = @ConstructorResult(
targetClass = ContractDTO.class,
columns = {
@ColumnResult(name = "contractEndDate", type = String.class),
@ColumnResult(name = "contractPlace", type = String.class),
@ColumnResult(name = "autoSeller", type = String.class),
@ColumnResult(name = "carNum", type = String.class),
@ColumnResult(name = "rentFullMonth", type = Integer.class),
@ColumnResult(name = "rentStartDate", type = String.class),
@ColumnResult(name = "rentEndDate", type = String.class),
@ColumnResult(name = "rentManageNum", type = String.class),
@ColumnResult(name = "cusName", type = String.class),
@ColumnResult(name = "repairCode", type = String.class),
@ColumnResult(name = "cusCode", type = String.class),
@ColumnResult(name = "insuAgeCode", type = String.class),
@ColumnResult(name = "insuGuarantee", type = String.class),
@ColumnResult(name = "insuSelfMoneyCode", type = String.class),
@ColumnResult(name = "rentSpecialCode", type = String.class),
@ColumnResult(name = "carInfo", type = String.class),
@ColumnResult(name = "depositPrice", type = Integer.class),
@ColumnResult(name = "totalPrice", type = Integer.class),
@ColumnResult(name= "monthlyPayPrice", type= Integer.class)
}
)
)
public class exampleEntitiy {
@Id
@Column(name="cntt_no")
private String cnttNo;
@Column(name="rq_no",length = 15)
private String rqNo;
@Column(length = 12)
private String cnttRqsNo;
@Column(length = 9)
private String lndCntdNo;
@Column(length = 15)
private String saleCnttNo;
@Column(length = 2)
private String cnttScnCd;
@Column(length = 2)
private String cnttStCd;
@Column(length = 2)
...
...
기본키 제외 다른키를 통해 DB에서 조회하려면 메소드를 Repository에 작성해줘야 한다.
이렇게 만든 Repo를 Service에서 가져와 코드를 작성한다.
package subin.OJT.Repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.math.BigInteger;
import java.util.List;
@Repository
public interface db_Repository extends JpaRepository<db, String> {
// 추가적인 메서드 선언이 필요한 경우 작성
// <T, ID> 형식, ID의 type을 맞춰줘야함.
List<KRCA_CNTT_I> findAllByCsmrSn(BigInteger CSMR_SN);
// @Query(value="", nativeQuery = true)
// List<ContractDTO> findContractInfo();
}
Service 예시
복잡한 쿼리문을 작성할 때는 createNativeQuery를 이용한다.
@Service
public class ContractService {
@PersistenceContext
private EntityManager entityManager;
public List<ContractDTO> getContractInfoByCSMRSN(BigInteger csmrSn){
String sql = "복잡한 sql 쿼리문~~~"
return entityManager.createNativeQuery(sql, "contractDTOMapping")
.setParameter("csmrSn", csmrSn)
.getResultList();
}
public List<ex> SelectContractById(String Id) {
Optional<ex> contractOptional= krca_cntt_i_repo.findById(Id);
List<ex> contract = new ArrayList<>();// List수정
if (contractOptional.isPresent()) {
logger.info("contractOptional.get() "+contractOptional.get());
contract.add(contractOptional.get());
return contract;
} else {
return contract;
}
} //성공
}