W8D1 - JPA

Onni·2021년 9월 27일
0

TIL

목록 보기
14/21

JPA 소개

1. JDBC

  • 자바 어플리케이션은 JDBC API를 이용하여 데이터계층과 통신
  • JDBC를 구현해 놓은 드라이버 클래스 객체들을 사용해서 JDBC API 인터페이스를 통해 통신
@Slf4j
public class JDBCTest {

    static final String JDBC_DRIVER = "org.h2.Driver";
    static final String DB_URL = "jdbc:h2:~/test";
    static final String USER = "sa";
    static final String PASS = "";

    static final String DROP_TABLE_SQL = "DROP TABLE customers IF EXISTS";
    static final String CREATE_TABLE_SQL = "CREATE TABLE customers(id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))";
    static final String INSERT_SQL = "INSERT INTO customers (id, first_name, last_name) VALUES(1, 'honggu', 'kang')";

    @Test
    void jdbc_sample() {
        try {
            Class.forName(JDBC_DRIVER); // JDBC DRIBER 구현체

            Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);
            log.info("Connection 획득");
            Statement statement = connection.createStatement();//statement 객체를 통해 쿼리 날림
            log.info("Statement 획득");

            log.info("쿼리 실행");
            statement.executeUpdate(DROP_TABLE_SQL);
            statement.executeUpdate(CREATE_TABLE_SQL);
            log.info("CRATED TABLE");

            statement.executeUpdate(INSERT_SQL);
            //ResultSet : 조회된 쿼리정보를 순환할수 있는 객체(업데이트성이 아닌 조회 쿼리에 이용)
            ResultSet resultSet = statement.executeQuery("SELECT id, first_name, last_name FROM customers WHERE id = 1");

            while(resultSet.next()) {
                String fullName = resultSet.getString("first_name")+""+resultSet.getString("last_name");
                //log.info(resultSet.getString("first_name"));
                log.info("CUSTOMER FULL_NAME:{}",fullName);
            }

            log.info("반납, 반납");
            statement.close();
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. 어떤 드라이버 쓸것인지 명시
  2. 컨넥션을 생성해 획득한 컨낵션을 통해 Statement객체를 만들고
    Statement객체를 통해 통신
  3. ResultSet을 통해 결과값을 조회
  4. 사용한 컨넥션 객체나 statement를 반납함

2. JDBC Template 이용

2-1 application.yaml에 설정정보 추가

2-2. JDBC Template Test

@Slf4j
@SpringBootTest //SpirngApplicationContext를 이용하기 위해
public class JDBCTest {

    static final String JDBC_DRIVER = "org.h2.Driver";
    static final String DB_URL = "jdbc:h2:~/test";
    static final String USER = "sa";
    static final String PASS = "";

    static final String DROP_TABLE_SQL = "DROP TABLE customers IF EXISTS";
    static final String CREATE_TABLE_SQL = "CREATE TABLE customers(id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))";
    static final String INSERT_SQL = "INSERT INTO customers (id, first_name, last_name) VALUES(1, 'honggu', 'kang')";

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Test
    void jdbcTemplate_sample(){
        jdbcTemplate.update(DROP_TABLE_SQL);
        jdbcTemplate.update(CREATE_TABLE_SQL);
        log.info("Created Table Using Jdbc Template");

        jdbcTemplate.update(INSERT_SQL);
        log.info("INSERTED CUSTOMER INFORMATION USING JDBC TEMPLATE");

        String fullName = jdbcTemplate.queryForObject(
                "SELECT * FROM customers WHERE id = 1",
                (resultSet,i) -> resultSet.getString("first_name")+" "+ resultSet.getString("last_name")
        );
        log.info("FULL_NAME : {}",fullName);
    }
}
  • SpringApplicationContext가 뜨면서 application.yaml정보를 이용해 빈을 생성할때 주입이 되면서 커넥션을 맺게됨
    • String fullName = jdbcTemplate.queryForObject(
      "SELECT * FROM customers WHERE id = 1",
      (resultSet,i) -> resultSet.getString("first_name")+" "+ resultSet.getString("last_name")
      );
      => 리절트셋을 다루는것도 querylForObject을 통해 손쉽게 조작
      dbcTemplate가 제공해주느느 메서드
  • JDBC Template를 이용해서, 데이터 계층에 접근이 가능
  • 기존 JDBC를 이용했을때의 반복적인 작업을 JDBC Template이 대신 수행(코드간략)
  • 한계: 자바 코드상에 sql문이 있음 -> 유지 보수 어려움 -> QueryMapper 등장

3. MYBATIS


type-aliases-package:
자바객체가 resulteset의 결과를 자동으로 매핑 해줌
그런 쿼리결과를 어떤객체에 매핑할지 패키지에 명시 해줄 것인지

  • CustomerMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kdt.lecture.kdtchapter1.repository.CustomerXmlMapper">
    <insert id="save">
        INSERT INTO customers (id, first_name, last_name)
        VALUES (#{id}, #{firstName}, #{lastName})
    </insert>

    <update id="update">
        UPDATE customers
        SET first_name=#{firstName},
            last_name=#{lastName}
        WHERE id = #{id}
    </update>

    <select id="findById" resultType="customers">
        SELECT *
        FROM customers
        WHERE id = #{id}
    </select>

    <select id="findAll" resultType="customers">
        SELECT *
        FROM customers
    </select>
</mapper>
  • Customer
//ResultSet의 결과를 개체에 매핑하기 위한 customer 객체
@Alias("customers") //테이블명 명시
public class Customer {
    private long id;
    private String firstName;
    private String lastName;

    public Customer(long id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

}

-MYBATISTest

@Slf4j
@SpringBootTest
public class MybatisTest {

    static final String DROP_TABLE_SQL = "DROP TABLE customers IF EXISTS";
    static final String CREATE_TABLE_SQL = "CREATE TABLE customers(id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))";

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    CustomerMapper customerMapper;

    @Test
    void save_test(){
        jdbcTemplate.update(DROP_TABLE_SQL);
        jdbcTemplate.update(CREATE_TABLE_SQL);

        customerMapper.save(new Customer(1L,"honggu","kang"));
        Customer customer = customerMapper.findById(1L);

        log.info("fullName:{} {}",customer.getFirstName(),customer.getLastName());
    }
}

자바 코드상에 직접 쿼리를 날리는거에서 인터페이스를 이용해 자바코드와 쿼리를 분리
메서드 호출을 통해

직접쿼리를 작성해 자바 코드객체와 매핑시켜 쿼리결과를 객체로 변화시켜 가져올 수 있었음

4. JPA

  • CustomerEntity
@Entity
@Table(name = "customers") //테이블 이름으로 명시, 없을땐 클래스이름
public class CustomerEntity {
    @Id
    private long id;
    private String firstName;
    private String lastName;


    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}
  • CustomerRepository
package com.kdt.lecture.kdtchapter1.repository;

import com.kdt.lecture.kdtchapter1.repository.domain.CustomerEntity;
import org.springframework.data.jpa.repository.JpaRepository;

//인자로 Entity객체와 id이름
public interface CustomerRepository extends JpaRepository<CustomerEntity,Long> {
}

-JPATest

@SpringBootTest
@Transactional
@Slf4j
public class JPATest {

    @Autowired
    CustomerRepository repository;

    @BeforeEach
    void setUp() {
    }

    @AfterEach
    void tearDown() {
        repository.deleteAll();
    }

    @Test
    void INSERT_TEST() {
        // Given
        CustomerEntity customer = new CustomerEntity();
        customer.setId(1L);
        customer.setFirstName("honggu");
        customer.setLastName("kang");

        // When
        repository.save(customer); // INSERT INTO ..

        // Then
        CustomerEntity entity = repository.findById(1L).get(); // SELECT * FROM ..
        log.info("{},{}", entity.getFirstName(), entity.getLastName());
    }


    @Test
    @Transactional //영속성 컨텍스트 안에서 관리하겠다
    void Update_Test() {
        // Given
        CustomerEntity customer = new CustomerEntity();
        customer.setId(1L);
        customer.setFirstName("honggu");
        customer.setLastName("kang");
        repository.save(customer);

        // When
        CustomerEntity entity = repository.findById(1L).get();
        entity.setFirstName("guppy");
        entity.setLastName("hong");

        // Then
       CustomerEntity updated = repository.findById(1L).get();
       log.info("{} {}", updated.getFirstName(), updated.getLastName());
    }

entity를 통해 테이블과 객체를 매핑

트랜잭션이 메서드가 실행할때 열리고 끝날떄 commit
영속성 컨텍스트에서 entitiy의 변경사항을 감지하고 있다가 entity의 속성이 변경되고
트랜잭션이 커밋 되면 자동으로 업데이트 쿼리가 날라감

-> 객체가 변경되면 테이블이 변경 : 테이블을 객체처럼 다룰수 있게 해줌
마이바티스나 ㅓㅔㅁqhek 간결하게 작성
변경에 유연함

jpa인터페ㅣㅇ스 중에서 하이버네이트 사용

profile
꿈꿈

0개의 댓글