W8D1 - JPA

44136 ワード

JPA概要


1. JDBC


  • Javaアプリケーション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();
            }
        }
    }
  • は、どのドライバを使用するかを示す
  • である.
  • インタフェースを作成し、取得したインタフェースからステータスオブジェクトを作成します.
    Statementオブジェクトによる通信
  • ResultSetクエリ結果値
  • を使用する関連オブジェクトまたは文
  • を返します.

    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が表示されたときのアプリケーション.yaml情報を使用してアイドル注入を作成し、接続
  • を確立する.
  • String fullName = jdbcTemplate.queryForObject(
    "SELECT * FROM customers WHERE id = 1",
    (resultSet,i) -> resultSet.getString("first_name")+""+ resultSet.getString("last_name")
    );
    =>querylForObjectでコールバックセットを簡単に処理
    dbcTemplateが提供する方法
  • JDBCテンプレートを使用してデータ層
  • にアクセスする.
  • の代わりにJDBC Templateが既存のJDBCを使用する場合の繰返し動作(略記コード)
  • を実行する.
  • 制限:Javaコードにsql文がある->メンテナンスが困難->QuaryMapperに
  • が表示されます.

    3. MYBATIS




    type-aliases-package:
    Javaオブジェクトが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());
        }
    }
    クエリーをjavaコードに直接送信し、インタフェースを使用してjavaコードから分離します.
    メソッドによる呼び出し
    クエリーを直接作成してjavaコードオブジェクトにマッピングし、クエリー結果をオブジェクトに変換してインポートできます.

    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によるテーブルとオブジェクトのマッピング
    トランザクションはメソッドの実行時に開き、終了時にコミットされます.
    永続性コンテキストでエンティティの変更を検出すると、エンティティのプロパティが変更されます.
    トランザクションがコミットされると、更新クエリは自動的に失われます.
    ->オブジェクトが変更された場合、テーブルは変更されます:テーブルをオブジェクトのように動作させます
    簡潔に記入する
    柔軟な変更
    jpaインタフェースでhypernateを使用する