2018년 4월 10일 화요일

패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 14일차(게시판실습, GitHub)

  • mysql
    • 자동증가 함수를 이용하자.(기본 컬럼에 primary key를 적용하면 Index 검사 매회 실행한다.)
  • JDBC
    • java.sql 패키지를 이용한 Database프로그래밍을 JDBC 프로그래밍이라고 합니다. 
    • java.sql의 핵심인터페이스를 보면, 구현하는 클래스를 자바는 제공하지 않는다. 
    • java를 만든 사람들은 DBMS와 상관없이 같은 방법으로 프로그래밍을 하길 원했다.
      - 데이터베이스 프로그래밍에 대한 인터페이스를 정의하였다.
      - DBMS마다 구현하는 방법은 다르다. 그렇다면? DB제작사에서 해당 인터페이스를 구현한 클래스를 제공한다. --> JDBC 드라이버(*.jar)
    • 
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>6.0.6</version>
      </dependency>
  • 데이터베이스 프로그래밍은 어떻게 하는가?
    • DB접속
    1. DB접속 1번째(java.sql) : 예전 연결방식으로 잘 쓰지않는다.
      https://docs.oracle.com/javase/8/docs/api/index.html?java/sql/package-summary.html
      Class.forName("드라이버 클래스이름"); //DBMS마다 이름이 다르다.
      // dburl은 DBMS마다 형식이 다르다.
      Connection conn = DriverManager.getConnection(dburl, dbid, dbpassword);
    2. 
      spring.datasource.driver-class-name=com.mysql.jdbc.Driver
      spring.datasource.url=jdbc:mysql://localhost:3306/helloboard?useUnicode=true&characterEncoding=utf8
      spring.datasource.username=fastcamp
      spring.datasource.password=fastcamp
      
    3. DB접속 2번쨰(java.datasource)
      https://docs.oracle.com/javase/8/docs/api/javax/activation/DataSource.html
      // javax.sql.DataSource
      // 커넥션을 얻는다.
      // DataSource ----> 커넥션풀객체(Connection들을 여러개 가짐) ---> DB
      // DataSource를 구현한 객체가 필요합니다.
      DataSource dataSource = ....;
      Connection conn = dataSource.getConnection();
      DataSource구현을 하고 있고 커넥션 풀이라고도 부른다. DB에 연결하기 위해서는 Driver를 사용합니다.
      
      <dependency>
              <groupId>org.apache.commons</groupId>
              <artifactId>commons-dbcp2</artifactId>
              <version>2.1.1</version>
      </dependency>
      
    • SQL을 준비한다. (문자열을 준비)
      • // role_id가 자동으로 생성된다면 다음과 같이 insert
        insert into ROLE( description ) values ( 'ADMIN' )
        // role_id가 자동으로 생성되지 않는다면
        insert into ROLE (role_id, description) values ( 500, 'ADMIN' );
        //프로그래밍을 한다.
        //나쁜 예제 : + 연산자로 sql을 작성한다. SQL Injection 을 당할 수있다. 성능이 느려진다.
        // DBMS에서 SQL을 실행하면, DBMS는 SQL을 분석한 후 실행한다. 분석하는 시간이 오래걸린다.
        // 완전히 동일한 SQL은 이미 분석한 결과를 사용하여 실행한다. 분석을 한 결과는 캐싱에 남기 때문에.. (대소문자 구분한다.)
        String sql = "insert into ROLE (role_id, description) values ( " + id + ", '" + description + " ');
        //좋은예제
        // 물음표 부분만 제외하고 분석됩니다. 개발자는 이 물음표에 나중에 값을 채운 후 실행한다.
        // 물음표에 값을 채우는 것을 바인딩한다. 물음표의 순서는 1부터 시작한다.
        String sql = "insert into ROLE (role_id, description) values ( ? , ? );
    • DB에서 SQL을 실행할 준비를 시킨다.
      • PreparedStatement ps = conn.prepareStatement(sql);
        //물음표부분을 바인딩 한다. 각각의 type에 맞게
        ps.setInt(1, 500); // 첫번째 물음표에 500을 설정
        ps.setString(2, "ADMIN") // 두번째 물음표에 ADMIN설정
    • SQL이 준비가 되어있다면, SQL을 실행한다.
      • ps.execute()
        int count = ps.excuteUpdate() // insert, update, delete sql을 실행
        ResultSet rs = ps.executeQuery() // select를 실행. (0, 1건이 나올경우), 0건이상
    • Select일 경우
      • 0,1건 Select일 경우
        • ResultSet은 select한 결과를 참조하는 인터페이스다. ps.executeQuery()가 실행되면, 실행된 결과는 DBMS에 있다.
        • // 한건을 읽어온다. 한건이라는 것은 record를 말한다. 여기서 record란 select다음에 나온 컬럼들을 말한다.
          //읽어오지 못하면 false를 반환하고, 읽어오면 true를 반환한후 다음 레코드를 참조한다.
          if(rs.next()) { //한건의 record를 읽어온다. select role_id, description from ROLE where role_id = ?
          int roleId = rs.getInt(1); // 첫번째 컬럼의 값을 읽어온다.
          String description = rs.getString(2); // 두번째 칼럼의 값을 읽어온다.
          }
    • 마지막 처리
      • ResultSet을 close(), PreparedStatement를 close(), Conntction을 close();
        Finally를 하거나 try - with - resources구문을 이용하거나 한다.
  • DispatcherServlet는 ContextLoaderListener를 부모로 가진다. ContextLoaderListener는 자식에 접근 못한다.
  • DispatcherServlet에서는 프리젠테이션 레이어 처리를 한다. Service, Repository 를 처리한다.
  • DispatcherServlet 끼리는 서로 참조하지 못한다.
    • ContextLoaderListener 구조
      • WebApplicationContext
        • 스프링설정
    • DispatcherServlet -> path : /board
      • WebApplicationContext
        • 스프링설정
    • DispatcherServlet -> path : /shop 
      • WebApplicationContext
        • 스프링설정
  • lombok Annotation
    • 관련된 부분이 오류나면 intelliJ lombok 검색하면 셋팅하는 방법이 나온다.
    • 컴파일 전에 자동으로 코드를 생성한다.
    • @Setter
    • @Getter
    • @ToString
    • @AllArgsConstructor
    • @NoArgsConstructor
  • Spring JDBC는 기존 JDBC프로그래밍을 아주 간단하게 할 수 있도록 도와준다.
    • BeanPropertySqlParameterSource는 자동으로 Map객체를 만들어 준다.
    • JdbcTemplate, dataSource 이 핵심객체이다.
    • SimpleJdbcInsert는 insert를 쉽게 도와주는 객체이다. 
    • RowMapper는 한건의 recode를 쉽게 객체에 담아 줄수 있도록 도와준다.
      jdbc에서 RsultSet으로부터 칼럼별로 값을 읽어오는 것을 도와주는 것
    • 테이블에서 자동으로 id가 생성될 경우는 usingGeneratedKeyColumns를 사용한다.
    • where 조건문이 없을때 Collections.emptyMap()를 활용한다.
    • 자동으로 생성되는 id 는 executeAndReturnKey(params).intValue() 을 통해 pk를 반환할 수 있다.
    • Map형태로 Collections.singletonMap를 사용하여 jdbc에 바인딩 한다.
    • SqlParameterSource params = new BeanPropertySqlParameterSource(VO클래스)는 VO클래스에 있는 변수들을 자동으로 바인딩 해준다.
    • @Repository
      public class RoleDao {
          // Spring JDBC는 기존 JDBC기존 프로그래밍을 아주 간단하게 할 수 있도록 도와준다.
          // JdbcTemplate, dataSource 이 핵심객체이다.
          private NamedParameterJdbcTemplate jdbc;
          // insert를 쉽게 도와주는 객체이다.
          private SimpleJdbcInsert insertAction;
          // RowMapper는 한건의 recode를 쉽게 객체에 담아 줄수 있도록 도와준다.
          // jdbc에서 RsultSet으로부터 칼럼별로 값을 읽어오는 것을 도와주는 것
          private RowMapper rowMapper = BeanPropertyRowMapper.newInstance(Role.class);
      
          public RoleDao(DataSource dataSource) {
              this.jdbc = new NamedParameterJdbcTemplate(dataSource);
              this.insertAction = new SimpleJdbcInsert(dataSource)
                      .withTableName("ROLE"); //테이블명
      //                .usingGeneratedKeyColumns("id"); // 자동으로 id가 생성될 경우
          }
      
          public List selectAll() {
              //  Collections.emptyMap() -> new HashMap 과 같음
              return jdbc.query("select role_id, description from ROLE order by role_id", Collections.emptyMap(), rowMapper);
          }
      
          public int insertRole(Role role){
              SqlParameterSource params = new BeanPropertySqlParameterSource(role);
              // 자동으로 id를 생성할 경우에는 아래와 같이 생성된 pk를 반환할 수 있다.
      //        return insertAction.executeAndReturnKey(params).intValue();
              int count = insertAction.execute(params);
              return role.getRoleId();
          }
      
          public int deleteRole(int roleId){
              Map params = Collections.singletonMap("roleId", roleId);
              return jdbc.update("delete from ROLE where role_id = :roleId", params); //Map형식으로 활용 , :바인딩 처리
          }
      
          public int updateRole(Role role){
              SqlParameterSource params = new BeanPropertySqlParameterSource(role); //자동으로 map객체를 만들어 준다.
              return jdbc.update("update ROLE set description = :description where role_id = :roleId", params);
          }
      
          public Role selectRole(int roleId){
              Map params = Collections.singletonMap("roleId", roleId);
              try{
                  Role role = jdbc.queryForObject("select role_id, description from ROLE where role_id = :roleId", params, rowMapper);
                  return role;
              }catch(){
                  return null;
              }
          }
      }
      
Share:

0 개의 댓글:

댓글 쓰기