반응형

ioc 작성 x

 

jdbc

jdbc #ex1

Exam0110 -> MariaDB java Client 설치 및 Driver 사용법

              // 1. mvnrepository.com - MariaDB Java Client 검색 - 버전 선택 -스크립트 복사 

              // 2. search.maven.org - search 창에 mariadb jdbc 검색 - mariadb jdbc client 클릭 - 버전 선택

              //  - 오른쪽 Gradle Groovy DSL - 스크립트 복사 

              // build.gradle에 붙혀넣기 - powershell 해당 경로 - gradle cleanEclipse - gradle eclipse

              // 이클립스 refresh // 프로젝트에 mariadb jdbc driver 라이브러리가 추가되었는지 확인

              // JDBC 드라이버 로딩 방법1 // java.sql.Driver 규칙에 따라 정의된 클래스를 로딩한다.

              // Driver 구현체 // JDBC의 정보를 알려준다. // DBMS에 연결작업을 수행 //

              // Driver 구현체를 생성하여 DriverManager에게 등록해 사용한다. // DriverManager가 Driver 구현체 관리.

              // DBMS 연결 요청이 들어오면 해당 DBMS의 Driver 구현체를 찾아 작업을 위임한다.

              // java.sql.Driver mariadbDriver = new org.mariadb.jdbc.Driver(); // Driver 구현체의 인스턴스 생성

              // DriverManager.registerDriver(mariadbDriver); // Driver 인스턴스를 드라이버 관리자에 등록

              // java.sql.Driver driver = DriverManager.getDriver("jdbc:mariadb:");

              // DriverManager.getDriver("jdbcUrl"); // DriverManager에 등록된 Driver 인스턴스 확인

              // jdbcUrl // jdbc:[DBMS]://서버주소.포트번호/데이터베이스명

Exam0111 -> Driver 예외 발생 // 등록되지 않은 드라이버를 찾을 경우 // No suiterable // 에러 발생

Exam0120 -> JDBC 드라이버 로딩 방법2 // Driver 객체를 생성하면 자동으로 DriverManager에 등록한다.

               // new org.mariadb.jdbc.Driver(); // Driver구현체가 로딩될 때 인스턴스가 생성된다.

               // DriverManager.registerDriver(mariadbDriver) // 인스턴스 생성 및 register를 할 필요없다.

Exam0130 -> JDBC 드라이버 로딩 방법3 //  Driver 구현 클래스 로딩과 자동 등록

               // java.sql.Driver 인터페이스를 구현한 클래스를 로딩하면, 자동으로 DriverManager에게 등록

               // Class.forName("org.mariadb.jdbc.Driver"); 

               // Class.forName("fully-qualified class name(패키지명을 포함한 클래스명)")

               // 장점 // 클래스를 지정하는 대신 클래스 이름을 지정하기 때문에 다른 클래스로 쉽게 바꿀 수 있다.

               // 따라서 특정한 Driver 구현체에 종속되지 않게 만들 수 있다.

               // 해당 Class에서 static블록으로 생성하기 때문에 한번만 실행된다.

               // DriverManager에 Driver 인스턴스는 하나만 등록된다.

Exam0140 -> JDBC 드라이버 로딩 방법4 // Driver 구현체 자동 로딩

               // DriverManager 로딩 절차

               // 1. jdbc.drivers 시스템 프로퍼티에 지정된 구현체를 찾아 로딩

               // jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver

               // Driver 구현체는 'system class loader'를 통해 로딩된다.

               // 시스템 프로퍼티 설정 방법 

               // 1) eclipse 실행표시 오른쪽 아래화살표 클릭 - Run Configurations - arguments - VM agruments -

               // -Djdbc.drivers=com.eomcs.jdbc.ex1.MyDriver 입력(MyDriver 미리 설정) - run // 자동 부팅 된 것을 확인

               // 2) 프로그램 코드에서 설정 // System.setProperty("jdbc.drivers", "com.eomcs.jdbc.ex1.MyDriver");

Exam0141 -> DriverManager 로딩 절차2

               // jar 파일 안에 META-INF/services/java.sql.Driver 파일을 찾는다.

               // 'service-provider loading' 절차에 따라 이 파일에 등록된 클래스를 로딩

               // jar 파일에 해당 정보가 있다면, 따로 java.sql.Driver 구현체를 명시적으로 등록하지 않아도 된다.

               // mariadb JDBC 드라이버 jar 파일은 이 정보가 들어 있다. // jar파일 등록하는 방법?

               // Exam0110에서 build.gradle에 넣어 실행할때 생기는 그 것이다.

              // java.sql.Driver driver = DriverManager.getDriver("jdbc:mariadb:"); // 결론 이렇게 작성하면 자동 등록된다.

Exam0210 -> DBMS에 연결하기 

               //  java.sql.Connection con = null;

               // con = DriverManager.getConnection("jdbc:mysql://localhost:3306/studydb", "study", "1111");

               // "jdbc:mysql://서버주소:포트/데이터베이스명", "DBMS 사용자 아이디", "DBMS 사용자 암호"

               // Driver 구현체는 DBMS와 연결한 후 소켓 정보를 갖고 있는 java.sql.Connection 구현체를 리턴한다.

Exam0220 -> try-with-resources

Exam0310 -> Statement 객체

               // java.sql.Connection con = DriverManager.getConnection(

               // "jdbc:mysql://localhost:3306/studydb?ser=study&password=1111");

               // java.sql.Statement stmt = con.createStatement(); // java.sql.Statement 구현 객체

               // SQL문을 DBMS의 형식에 따라 인코딩하여 서버에 전달하는 일을 하는 객체

               // Statement 객체 사용법

               // 1. DML(Data Manipulation Language) // INSERT/UPDATE/DELETE 등 DML 관련 SQL문 전송

               // executeUpdate() // 리턴값 // 변경(insert/update/delete)된 데이터의 개수

               // 2. DQL(Data Query Language) // SELECT 등 DQL 관련 SQL문 전송

               // executeQuery() // 리턴값 // 서버에서 데이터를 가져오는 일을 할 객체

Exam0320 -> SQL에서 데이터를 JAVA로 가져오는 방법.

               // java.sql.ResultSet rs = stmt.executeQuery("select * from x_board order by board_id desc");

               // ResultSet 객체 // 서버에서 결과를 가져오는 일을 할 객체

               // ResultSet 객체를 사용하여 서버에서 select의 결과 한 레코드(row)를 가져온다. 

               // boolean isReceived = rs.next(); // 레코드(Recode) // select를 실행한 후 생성된 결과 // 

               // 가져왔으면 true, 가져올 게 없다면 false 

               // int, number: getInt() // char, varchar, text: getString() // date, datetime: getDate() // float: getFloat()

               // getXxx(컬럼번호) // select 문에 나열한 컬럼의 순서를 지정한다. // 번호는 0부터가 아니라 1부터이다.

               // rs.getInt(1), rs.getString(2), rs.getString(3), // 컬럼의 번호를 지정 것은 코드를 읽을 때 불편하다. 

Exam0330 -> DBMS에 SQL문 보내기

               // getXxx(컬럼명) // rs.getInt("board_id"), rs.getString("title"), rs.getString("contents"),

Exam0340 -> 반복문 사용

Exam0341 -> getString() // 컬럼의 타입과 상관없이 getString()으로 값을 꺼낼 수 있다.

Exam0350 -> 데이터 업데이트 executeUpdate() // ""안에 update를 넣는다.

               // DBMS 서버에 update 문을 보낸다. // 리턴 값: 변경된 레코드의 개수

               // stmt.executeUpdate( "update x_board set view_count = view_count + 20" + " where board_id > 1");

Exam0360 -> 데이터 삭제 executeUpdate() // ""안에 delete를 넣는다. 

               // int count = stmt.executeUpdate( "delete from x_board where board_id > 5");

 

jdbc #ex2

Exam0110 -> list.add()  // "" insert 넣는다. 

              // String sql = String.format( "insert into x_board(title,contents) values('%s','%s')", title, contents);

              // int count = stmt.executeUpdate(sql);

Exam0120 -> list.list() jdbc #ex1 Exam0320, Exam0330과 같다.

Exam0130 -> list.detail() // ResultSet rs = stmt.executeQuery( "select * from x_board where board_id = " + no))

Exam0140 -> list.update()

Exam0150 -> list.delete()

Exam0210 -> SQL 삽입 공격 

              // 입력 문자열에 SQL 명령을 삽입하여 프로그램의 의도와 다르게 데이터를 조작하는 행위.

Exam0220 -> SQL 삽입 공격 대비 

              // PreparedStatement는 미리 SQL 문장을 준비하여 값을 삽입하는 기법이다.

              // SQL 문장을 준비할 때, 값이 들어 갈 자리에 ? 로 표시한다. // ? 를 "in-parameter"라 부른다.

              // SQL을 서버에 전달하기 전에 in-parameter 자리에 값을 넣는다.

              // PreparedStatement.setXxx(in-parameter 인덱스, 값);

PreparedStatement stmt = con.prepareStatement("update x_board set title = ?, contents = ? where board_id = ?")) {

              // stmt.setString(1, title);  stmt.setString(2, contents);  stmt.setString(3, no);

              // int count = stmt.executeUpdate(); // ?에 들어갈 값을 다 채우고 stmt.executeUpdate()를 해야한다.

              // in-parameter 인덱스 // ? 문자가 등장하는 순서대로 1부터 번호를 부여한다.

              // 작은 따옴표를 그냥 일반 문자로 취급 // 실무에서는 거의 무조건 PreparedStatement만 사용한다.

              // Statement vs PreparedStatement

              // PreparedStatement가 SQL 문장과 값이 분리되어 있기 때문에 작성하거나 읽기 쉽다

              // PreparedStatement는 SQL 문장과 값이 분리되어 다뤄지기 때문에 해킹할 수 없다. // SQL 삽입 공격 대비

              // PreparedStatement는 setXxx() 메서드를 호출하여 값을 설정하기 때문에 바이트 배열의 값을 다룰 수 있다.

    // PreparedStatement가 executeUpdate() 호출시 SQL 문법을 분석하지 않아, 반복 실행할 때 Statement 보다 빠르다.

Exam0310 -> list.add()  // preparedStatment 형식으로 변경.

               // PreparedStatement stmt = con.prepareStatement("insert into x_board(title,contents) values(?,?)");)

               // PreparedStatement 으로 선언하는데, prepareStatement // 메서드는 d가 안들어간다.

Exam0320 -> list.list() // preparedStatment 형식으로 변경.

Exam0330 -> list.detail() // preparedStatment 형식으로 변경.

Exam0340 -> list.update() // preparedStatment 형식으로 변경.

Exam0350 -> list.delete() // preparedStatment 형식으로 변경.

Exam0410 -> auto increment PK값 리턴 받기 // PreparedStatement 객체를 얻을 때 옵션을 지정한다.

               // PreparedStatement stmt = con.prepareStatement("insert into x_board(title,contents)

               // values(?,?)", Statement.RETURN_GENERATED_KEYS);)

               // prepareStatement(sql문, 자동 생성된 PK 값 리턴 여부) // Statement.RETURN_GENERATED_KEYS

               // ResultSet rs = stmt.getGeneratedKeys() // insert 수행 후 자동 생성된 PK 값은 따로 요구

               // no = rs.getInt(1); // 자동 생성된 PK 값을 꺼낼 때는 따로 컬럼 이름이 없기 때문에 컬럼 인덱스로 꺼낸다.

Exam0420 -> auto increment PK값 리턴 받기 반복문 사용

Exam0510 -> 트랜잭션 // autocommit = true // autocommit일 경우 오류의 경우에도 commit을 해버린다.

               // 원하는데로 컨트롤 할 수 없다. // autocommit을 false로 하고 사용하자.

Exam0520 -> 트랜잭션 다루기 // 여러개의 데이터 변경 작업을 한 단위로 묶은 것. // commit & rollback

               // con.setAutoCommit(false); // 커넥션 객체의 오토커밋을 false로 지정한다 // DBMS의 임시 테이블에 보관

               // 이후부터 con으로 실행하는 모든 SQL은 commit을 요청하기 전까지 table에 결과를 적용하지 않는다.

               // con.commit(); // 필요한 모든 작업을 수행하고 // 서버의 요청한 작업을 처리할 것을 명령

               // commit()을 호출하지 않으면 서버에 요청한 데이터 변경 작업은 자동 취소

               // con.rollback(); // 서버의 요청한 작업을 취소할 것을 명령함. // 명시적으로 작업을 취소하는 것.

               // rollback()을 호출하지 않고, 

               // 커넥션을 공유하는 상황에서는 이렇게 명시적으로 작업 취소를 명령하는 것이 좋다.

 

jdbc #ex3

Exam0110 -> list.add() DBMS 작업 분리 // BoardDao생성 // DBMS 작업 전담하게 작업.

               // DBMS 작업을 캡슐화하면, 코드가 더욱 직관적으로 바뀐다. 

Exam0120 -> list.list() DBMS 작업 분리

Exam0130 -> list.detail() DBMS 작업 분리

Exam0140 -> list.update() DBMS 작업 분리

Exam0150 -> list.delete() DBMS 작업 분리

 

mybatis

mybatis #ex01

Exam0110 -> Data Persistence Framework // 데이터의 영속성(등록,조회,변경,삭제)을 대신 처리해주는 프레임워크

               // SQL Mapper // 직접 SQL 문을 작성 // 각각의 DBMS에 최적화된 SQL을 작성할 수 있다.

               // DBMS마다 미미하게 다른 SQL을 작성해야 하는 번거로움이 있다. // 예) Mybatis 등

               // OR Mapper // 전용언어 및 문법(Domain-Specific Language;DSL)을 사용하여 작성

               // 실행할 때 DBMS에 맞춰서 SQL을 생성하여 실행한다.

               // DBMS마다 SQL문을 작성할 필요가 없어 편리하다. // DBMS에 최적화된 SQL을 실행할 수 없다.

               // 즉 DBMS의 특징을 최대로 활용할 수 없다. // 예) Hibernate, TopLink 등 

               // 1. 의존 라이브러리 추가

               // Mybatis 도입 // search.maven.org - mybatis검색 - 오른쪽 Gradle Groovy DSL 버전 스크립트 복사 -

               // build.gradle 에 추가 - gradle cleanEclipse - gradle eclipse - 라이브러리 추가 확인

               // 2. mybatis 설정 파일 준비 // mybatis-config.xml 생성

               // https://blog.mybatis.org/ - 오른쪽 MyBatis for Java에 Github Project - mybatis-3 -

               // 스크롤 맨 밑 Essentials의 See the docs - Getting started - The configuration XML file 밑 스크립트 복사 

               // 복사한거 mybatis-config.xml 파일 이름으로 생성 

               // 3. DB 연결 정보를 담은 프로퍼티(properties) 파일 준비 // jdbc.properties 생성 및 편집

# key=value
jdbc.driver=org.mariadb.jdbc.Driver
jdbc.url=jdbc:mariadb://localhost:3306/studydb
jdbc.username=study
jdbc.password=1111

               // jdbc.driver=  jdbc.url=   jdbc.username=   jdbc.password= // 맞는 값을 입력한다.

               // 중요한 것은 오타가 발생하면 안되고, 맨 뒤에 공백이 있으면 안된다. // 공백여부 꼭 확인

               // 4. mybatis 설정 파일(mybatis-config.xml) 편집 // mybatis-config.xml 편집

               // <properties resource="com/eomcs/mybatis/ex01/jdbc.properties"></properties>

               // jdbc.properties 파일의 내용을 읽어온다. // 3번 파일의 경로를 넣는다.

               // 읽어온 정보는 ${프로퍼티명} 문법을 이용하여 그 값을 사용할 수 있다.

               // <environments default="development"> // DBMS에 연결할 때 사용할 정보를 설정

               // 여러 개의 연결 정보를 설정해두고 그 중에 사용할 정보를 지정할 수 있다.

               // <environment id="development"> // 각각의 연결 정보는 다음과 같이 environment 태그에 설정한다.

               // <transactionManager type="JDBC"/> // 트랜잭션 관리 방식을 지정한다.

               // <dataSource type="POOLED"> // DB 커넥션 풀에 관련된 정보와 DB 연결 정보를 설정한다.

               // 이제 개발자가 DB 커넥션 풀을 다룰 필요가 없다. // mybatis 프레임워크에서 관리한다.

               // <property name="driver" value="${jdbc.driver}"/> // <property name="url" value="${jdbc.url}"/>

               // <property name="username" value="${jdbc.username}"/>

               // <property name="password" value="${jdbc.password}"/>

               // ${위의 .properties 파일에 저장된 프로퍼티명}

               // <mapper resource="step25/ex5/BoardMapper.xml"/> // 5.번 단계

               // SQL문을 모아둔 파일(SQL 맵퍼 파일이라 부른다)을 지정한다.

               // 맵퍼 파일의 경로를 지정할 때 classpath 경로를 사용해야 한다. // 경로는 . 대신 /를 사용한다.

               // 5. SQL 문장을 작성할 파일 준비 // BoardMapper.xml 생성 및 편집

               // 2번 경로 - Exploring Mapped SQL Statements 밑 스크립트 복사 - 복사한거 맞는 파일 이름으로 생성 

               // <mapper namespace="BoardMapper"> 

               // SQL 맵퍼 파일이나 맵퍼 파일의 경로를, SQL을 사용할 인터페이스나 클래스 경로 그룹명으로 지정한다.

               // <select id="selectBoard" resultType="com.eomcs.mybatis.ex01.Board">

  <select id="selectBoard2" resultType="com.eomcs.mybatis.ex01.Board">
    select 
      board_id as no,
      title,
      contents as content,
      created_date registeredDate,
      view_count viewCount
    from x_board
  </select>

               // 아래의 코드를 selectBoard로 호출하게끔 한다. // 즉 별명을 붙히는 거라고 생각하면 이해가 쉽다. 

               // resultType은 결과적으로 어떤 형태를 나타나게 하느냐를 이야기 한다.

               // DB에는 board_id, contents, created_date, view_count의 형태로 저장이 되어 있는 것을,

               // Java에는 Board Class에 정의가 no, content, registeredDate, viewCount 여기에 넣는다는 의미이다.

               // 즉 DB에서 Java로 가져올 때 저 데이터가 어떤 것을 대응(의미)하는지를 말한다고 생각하면 된다.

               // mybatis 사용

               // 1. mybatis 설정 파일을 읽을 InputStream 도구를 준비한다. 

               // 직접 시스템 파일 경로를 지정한다. // 소스 파일 경로를 지정하지 않는다.

               // 컴파일된 후 XML파일이 놓이는 경로를 지정한다.

               // 자바 패키지에 작성한 일반 파일은 빌드 디렉토리에 복사된다.

               // 예) 프로젝트폴더/bin/main/com/eomcs/mybatis/ex01/mybatis-config.xml

         // InputStream inputStream = new FileInputStream("./bin/main/com/eomcs/mybatis/ex01/mybatis-config.xml");

               // 2. SqlSessionFactoryBuilder를 만들어 줄 빌더 객체 준비

               // SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();

               // 3. SqlSession 객체를 만들어 줄 팩토리 객체 준비

               // mybatis 설정 파일을 가지고 Builder를 이용하여 SqlSessionFactory 객체를 생성한다.

               // 설정 파일의 경로를 직접 지정하지 말고, InputStream에 담아 InputStream을 넘겨주게끔 한다.

               // SqlSessionFactory factory = factoryBuilder.build(inputStream);

               // 4. SQL을 실행시키는 객체 준비

               // SqlSession sqlSession = factory.openSession(); // openSession()은 수동 커밋의 객체를 리턴

               // openSession(boolean autoCommit) // 자동 커밋으로 SQL을 다루고 싶을때 사용

Exam0111 -> mybatis 설정파일을 직접 지정하지 않는다. // Exam0110은 직접 지정한 경우

               // 1. mybatis 설정 파일을 읽을 InputStream 도구를 준비한다. 

               // mybatis 설정 파일의 경로를 직접 지정하면,

               // 애플리케이션 배포 경로가 바뀔 때마다 소스를 변경하고 다시 컴파일 해야 한다.

               // InputStream InputStream = new FileInputStream(

               // Resources.getResourceAsStream("com/eomcs/mybatis/ex01/mybatis-config.xml");

               // Resources 클래스의 메서드를 이용 // 파라미터에 mybatis 설정 파일 경로를 지정 // .대신 /를 사용

               // 자바 패키지 경로를 그대로 알아서 찾아간다. // bin/main... 경로를 알아서 찾아감. 

               // 자바 패키지 경로에서 찾기 때문에 mybatis 설정 파일은 반드시 자바 패키지 경로에 있어야 한다.

               // 이후 단계는 Exam0110과 동일하다.

Exam0112 -> mybatis 코드 정리 // Exam0110, Exam0111 주석 지우고 코드 정리한 것.

Exam0120 -> SQL 문 실행

            // select 문장 // sqlSession.selectList() // 목록 리턴 // sqlSession.selectOne() // 한 개의 결과 리턴 

            // insert 문장 // sqlSession.insert() // update 문장 // sqlSession.update() // delete 문장 // sqlSession.delete()

            // insert/update/delete인 경우 아무거나 호출해도 된다. // update로 처리가 된다 내부적으로.

            // 하지만 일관된 유지보수를 위해 메서드를 구분하여 사용하자.

            // List list = sqlSession.selectList("BoardMapper.selectBoard");

            // 메서드 사용법 selectList(SQL문 이름, 파라미터값) // SQL문 이름 = 그룹명 + "." + SQL문장 아이디

            // 그룹명 // <mapper namespace="그룹명">...</mapper> // BoardMapper.xml

            // SQL 문장 아이디 // <select id="SQL문장 아이디">...</select> // BoardMapper.xml

            // 파라미터 값 // primitive type 및 모든 자바 객체가 가능 // 여러 개의 값을 전달할 때는 Map에 담아 넘긴다.

            // selectList 동작 원리

            // 1. resultType에 지정한 클래스의 인스턴스를 생성한다.

            // 컬럼 이름과 일치하는 프로퍼티(setter)를 찾아 값을 입력한다.

            // 일치하는 프로퍼티가 없다면 값을 입력하지 못한다.

Exam0121 -> mybatis // 컬럼 이름과 프로퍼티 이름을 일치시키기

            // BoardMapper.xml // Java 컬럼과 SQL 컬럼 이름 설정방법은 애초에 다르다.

            // board_id as no, // as를 사용하여 Java에서의 컬럼명과 SQL에서의 컬럼명을 연결시켜준다. // as 생략가능

Exam0210 ->mybatis // 클래스 별명 지정하기

            // mybatis 설정 파일에서 fully-qualified class name 을 사용하는 대신 짧은 이름으로 대체할 수 있다.

            // fully-qualified class name // 패키지 명을 포함한 클래스명

            // <typeAliases> <typeAlias type="com.eomcs.mybatis.ex01.Board" alias="Board"/> </typeAliases>

            // mybatis-config02를 참조하면 된다. // com.eomcs.mybatis.ex01.Board에 Board라는 별명을 붙힌 것이다.

            // typeAliases를 설정할 때에는 /가 아닌 .을 사용한다. // 이유는 Java에서 사용하는 경로이기 때문에 .이다.

 

mybatis #ex02

Exam0110 -> 컬럼 이름과 프로퍼티 이름 // 컬럼 이름과 프로퍼티 이름이 다르면 데이터를 가져오지 못한다.

  <select id="selectBoard" resultType="Board">
    select 
      board_id, <!-- Board.setBoard_id() 호출 -->
      title,    <!-- Board.setTitle() 호출 -->
      contents, <!-- Board.setContents() 호출 -->
      created_date, <!-- Board.setCreated_date() 호출 -->
      view_count    <!-- Board.setView_count() 호출 -->
    from x_board
  </select>  
       

            // 위의 SQL문을 mybatis는 내부에서 다음과 같은 코드로 실행할 것이다.

ArrayList<Board> list = new ArrayList<>();
       
while (rs.next()) {
    Board board = new Board();
    board.setBoard_id(rs.getNo("board_id")); // 이런 셋터가 없다.
    board.setTitle(rs.getString("title")); // 이 셋터는 있다.
    board.setContents(rs.getString("contents")); // 이런 셋터가 없다.
    board.setCreated_date(rs.getDate("created_date")); // 이런 셋터가 없다.
    board.setView_count(rs.getDate("view_count")); // 이런 셋터가 없다.
    list.add(board);
} 
return list;

Exam0120 -> 컬럼 이름과 프로퍼티 이름 // 컬럼 이름과 프로퍼티 이름이 같으면 데이터를 가져올 수 있다.

Exam0130 -> 컬럼 이름과 프로퍼티 이름 // 컬럼 이름과 프로퍼티 이름을 연결한다.

<mapper namespace="BoardMapper">
  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/>
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
  </resultMap>

          // <resultMap type="Board" id="BoardMap"> 

          // type // 자바 객체의 클래스명 또는 별명 // id // 연결 정보를 가리키는 식별자 

          // <id column="bno" property="no"/> <result column="titl" property="title"/>

          // <result column="테이블 컬럼명" property="자바 객체의 프로퍼티명"> // primary key 컬럼은 id 태그를 사용

          // column명과, property명이 같다면, 생략 가능하다. // 이름이 같으니깐 알아서 가져올 것이기 때문

          // <select id="selectBoard" resultMap="BoardMap">

          // 위에서 정의한 연결 정보를 사용하고 싶다면, resultMap="연결정보아이디" 를 설정한다.

          // 연결 정보를 사용하면, Exam0120처럼 일일히 연결시키지 않아도 된다. 

          // 원래는 사용시마다, 컬럼을 as로 연결을 했어야 하지만 resultMap을 한번 만들어두면,

          // as를 연결할 필요 없이 resultMap을 가져오면 된다.

Exam0210 -> SQL에 파라미터로 값 전달 // int 

          // SQL 문에 값 삽입하기 // in-parameter 지정하기 

          // parameterType에 지정된 객체의 프로퍼티 명을 사용하여 값을 삽입한다. // ex) #{프로퍼티명}

          // parameterType이 primitive/String/wrapper class인 경우, 아무 이름을 적어도 된다. // #{haha}

          // parameterType이 Map 객체인 경우는 map에 저장된 값의 key를 적는다. // #{key}

          // SQL을 실행할 때 파라미터로 넘어오는 값의 타입을 지정한다.

          // parameterType="값이 들어 있는 객체의 타입명 또는 별명"

      // int => _int // Integer => int // String => string // Map => map // HashMap => hashmap // Board => board

          // List list = sqlSession.selectList("BoardMapper.selectBoard1", 5); /

          // <select id="selectBoard1" resultMap="BoardMap" parameterType="int"> // where board_id > #{ohora}

          // BoardMapper04.xml // 파라미터 타입이 int라서 아무거나 입력 가능

Exam0211 -> SQL에 파라미터로 값 전달 // String

          // List list = sqlSession.selectList("BoardMapper.selectBoard2", "%ohora%");

          // <select id="selectBoard2" resultMap="BoardMap" parameterType="string"> // where title like #{haha}

          // BoardMapper04.xml // 파라미터 타입이 String라서 아무거나 입력 가능

Exam0212 -> SQL에 파라미터로 값 전달 // Map

          // HashMap<String, Object> params = new HashMap<>();

          // List list = sqlSession.selectList("BoardMapper.selectBoard3", params);

          // <select id="selectBoard3" resultMap="BoardMap" parameterType="map"> // limit #{startIndex}, #{size}

          // BoardMapper04.xml // 파라미터 타입이 Map이라서 저장된 값의 key를 이용한다.

  <select id="selectBoard3" 
          resultMap="BoardMap" 
          parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    limit #{startIndex}, #{size}
  </select>

Exam0220 -> SQL에 파라미터로 값 전달 // #{} 문법 // 오름차순

           // <select id="selectBoard1" resultMap="BoardMap" parameterType="string"> // order by #{colname} asc

           // BoardMapper05.xml // #{} 문법의 경우 파라미터에 값을 넣을 때 사용한다. // 

Exam0221 -> SQL에 파라미터로 값 전달 // ${}문법

           // <select id="selectBoard2" resultMap="BoardMap" parameterType="string"> // order by ${colname} asc

           // BoardMapper05.xml // ${} 문법의 경우 값을 SQL 문에 그대로 삽입한다. // 

Exam0222 -> SQL에 파라미터로 값 전달 // ${}문법의 단점 // SQL 삽입 공격

            // <select id="selectBoard3" resultMap="BoardMap" parameterType="string"> // ${sql}

            // SQL Mapper에서는 ${} 문법으로 SQL문을 받는다.

            // 단, 사용자가 입력한 값 그대로 파라미터에 넘긴다면 SQL 삽입 공격에 노출 될 수 있다.

            // 사용자가 입력한 값을 그대로 전달하지 않고, 개발자가 지정한 값을 전달한다는 전제 하에는 사용할 수 있다.

Exam0230 -> SQL에 파라미터로 값 전달 // 일반 객체

            // <insert id="insertBoard" parameterType="Board"> insert into x_board(title,content,created_date) 

            // values(#{title},#{content},now()) </insert> // '를 붙히면 안된다!

            // title과 content가 string이라고 해서 'title' 'content' 처럼 '를 붙히지 않는다. // 값으로 인식, 값으로 들어감.

            // parameterType="클래스명 또는 별명" // 일반 객체를 파라미터로 받을 수 있다. //

            // 일반 객체에서 값을 꺼내려면 프로퍼티(getter)명을 지정해야 한다. // getTitle(), getContent() 

            // sqlSession.commit(); // 작업이 끝난 후 commit 필수 // mybatis에서는 autocommit이 기본으로 false이다.

            // autocommit? // 

            // insert/update/delete 과 같이 데이터를 변경하는 작업은

            // 위험하기 때문에 DBMS의 임시 메모리에 그 작업 결과를 보관한다.

            // 클라이언트에서 최종적으로 변경을 허락해야만 진짜 테이블에 값을 반영한다

            // commit 명령을 내리지 않으면 insert/update/delete을 테이블에 반영하지 않는다. // close() 할 때 취소된다.

            // commit // 임시 메모리에 저장된 작업 결과를 실제 테이블에 반영시키는 명령

            // rollback // 임시 메모리에 저장된 작업 결과를 취소하는 명령

Exam0240 -> INSERT 실행 후 자동 증가된 PK값 가져오기

  <insert id="insertBoard" parameterType="Board"
          useGeneratedKeys="true" keyColumn="board_id" keyProperty="no">
    insert into x_board(title,contents,created_date) 
    values(#{title},#{content},now())
  </insert>  

           // keyColumn 중 "board_id" 값을 keyProperty 중 "no"값에 넣는다는 의미이다.

           // no의 경우 auto-increase로 DBMS에 넣는 즉시 생성되는데, Java에는 no값이 없는 상태이다.

           // useGeneratedKey를 설정하면, 자동으로 DBMS에서 Java의 noSetter를 호출해 값을 리턴해준다.

           // Java에서 별도로 코드 작업할 필요가 없다 // as 설정하면 알아서 Java Setter 호출하는 걸로 생각하자.

Exam0250 -> Update SQL 실행하기

           // Insert와 크게 다르지 않다. // 차이 점이라면 update이기 때문에 no값을 이미 알고 있다는 점.

           // 따라서 useGeneratedKey를 설정하면 안된다는 점의 차이 정도?

Exam0260 -> DeleteSQL 실행하기

    // 먼저 자식 테이블의 데이터를 지운다.
    int count = sqlSession.delete("BoardMapper.deleteBoardFile", 3);
    System.out.println(count);

    // 그런 후 부모 테이블의 데이터를 지운다.
    count = sqlSession.delete("BoardMapper.deleteBoard", 3);
    System.out.println(count);

           // delete의 경우 DBMS에 UK가 설정되어 있기 때문에 꼭 자식테이블의 데이터를 먼저 지워줘야 한다.

<mapper namespace="BoardMapper">

  <delete id="deleteBoard" parameterType="int">
    delete from x_board
    where board_id=#{value}
  </delete>
  
  <delete id="deleteBoardFile" parameterType="int">
    delete from x_board_file
    where board_id=#{value}
  </delete>  
</mapper>

           // 당연히 자식테이블의 데이터를 지우는 코드도 Mapper에 존재해야 한다.

           // 같은 Mapper 파일에 있을 필요는 없다. // 다른 Mapper파일에 존재한다면,

           // 자식 테이블의 데이터를 지우는 Mapper의 id를 먼저 호출 후 지우고, 

           // 부모 테이블의 데이터를 지우는 Mapper의 id를 후에 호출하면 된다.

 

mybatis #ex03

Exam0110 -> Dynamic SQL 다루기 // 조건문 사용 전

Exam0120 -> Dynamic SQL 다루기 // If조건문 사용 후

           // Dynamic SQL // 조건에 따라 SQL을 달리 생성하는 것  

  <select id="select3" resultMap="BoardMap" parameterType="int">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    <if test="no != null">
      where board_id = #{no}
    </if>
  </select>

           // if조건문 // <if test="조건">SQL문</if> // "no != null"일 때 where문을 추가하는 구조이다.

Exam0130 -> 파라미터로 Map을 넘겨받았을 때

  <select id="select4" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    <if test="item == 1">
      where board_id = #{keyword}
    </if>
    <if test="item == 2">
      where title like concat('%', #{keyword}, '%')
    </if>
    <if test="item == 3">
      where contents like concat('%', #{keyword}, '%')
    </if>
  </select>

           // 파라미터로 넘겨받은 map의 item 값에 따라 if문을 별도로 조정할 수 있다.

           // concat? // concat은 문자열을 합쳐주는 역할을 한다. // concat('%', #{keyword}, '%') // %keyword값% // 

Exam0140 -> if조건문에 or를 사용할 때 // 실행 오류

  <select id="select5" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    where
    <if test="no != null">
      board_id = #{no}
    </if>
    <if test="title != null">
      or title like concat('%', #{title}, '%')
    </if>
    <if test="content != null">
      or contents like concat('%', #{content}, '%')
    </if>
  </select>

           // 위 데이터의 문제점은 no != null이 false일때, 문제가 발생한다. // 가장 처음 조건문이 나타나지 않을 때

           // 앞에 가장 처음에 나오는 조건문이 존재하지 않기 때문에, or 조건자체가 오류가 되어버리는 것이다.

Exam0150 -> if조건문에 or를 사용할 때 // 실행 오류 해결 방법 1 // 의미없는 문구 추가

  <select id="select6" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    where 1=0
    <if test="no != null">
      or board_id = #{no}
    </if>
    <if test="title != null">
      or title like concat('%', #{title}, '%')
    </if>
    <if test="content != null">
      or contents like concat('%', #{content}, '%')
    </if>
  </select>  

           // 첫번째 if문이 나타나지 않을때를 대비하여 아예 1=0이라는 조건에 영향을 끼치지 않는 조건문을 넣는다.

Exam0160 -> if조건문에 or를 사용할 때 // 실행 오류 해결 방법 2 // <where> 사용

  <select id="select7" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    <where>
	    <if test="no != null">
	      board_id = #{no}
	    </if>
	    <if test="title != null">
	      or title like concat('%', #{title}, '%')
	    </if>
	    <if test="content != null">
	      or contents like concat('%', #{content}, '%')
	    </if>
    </where>
  </select>  

           // <where>을 사용하면, 첫번째 if문이 false여도 상관이 없다. // 첫 문장이 or가 붙어있어도 상관 없다.

Exam0170 ->if조건문에 or를 사용할 때 // 실행 오류 해결 방법 3 // trim 사용

  <select id="select8" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    <trim prefix="where" prefixOverrides="OR | AND"> 
      <if test="no != null">
        board_id = #{no}
      </if>
      <if test="title != null">
        or title like concat('%', #{title}, '%')
      </if>
      <if test="content != null">
        or contents like concat('%', #{content}, '%')
      </if>
    </trim>
  </select>  

           // trim prefix="where" prefixOverrides="OR | AND"

           // or/and 앞에 아무것도 없을 때 or/and 를 자동으로 제거한다.

           // 실무에서 Exam0150, Exam0160, Exam0170 셋 다 사용한다. // 선임 개발자마다 다르니 셋 다 알아둘 것.

Exam0210 -> <choose> 사용

    HashMap<String, Object> params = new HashMap<>();
    if (item.equals("1")) {
      params.put("item", "no");
    } else if (item.equals("2")) {
      params.put("item", "title");
    } else {
      params.put("item", "content");
    }
    params.put("keyword", keyword);

    List<Board> list = sqlSession.selectList("BoardMapper.select21", params);

           // item이 1일때 no를 넣고 // 2일때 title을 넣고 // 그 외는 content를 넣고 // keyword에는 keyword를 넣는다.

  <select id="select21" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    where
    <choose>
	    <when test="item == 'no'">
	      board_id = #{keyword}
	    </when>
	    <when test='item == "title"'>
	      title like concat('%', #{keyword}, '%')
	    </when>
	    <otherwise>
	      contents like concat('%', #{keyword}, '%')
	    </otherwise>
	  </choose>
  </select>  

Exam0220 -> <set> 사용 전

    if (params.get("title") != null && params.get("content") != null) {
      count = sqlSession.update("BoardMapper.update3", params);
    } else if (params.get("title") != null) {
      count = sqlSession.update("BoardMapper.update1", params);
    } else if (params.get("content") != null) {
      count = sqlSession.update("BoardMapper.update2", params);
    }
  
  <update id="update1" parameterType="map">
    update x_board set
      title=#{title}
    where board_id=#{no}
  </update>
  <update id="update2" parameterType="map">
    update x_board set
      contents=#{content}
    where board_id=#{no}
  </update>
  <update id="update3" parameterType="map">
    update x_board set
      title=#{title},
      contents=#{content}
    where board_id=#{no}
  </update>

           // 제목만 바꿀 경우, 내용만 바꿀 경우, 둘 다 바꿀 경우에 대해 각각의 update SQL을 준비한다.

           // Java 코드로도, SQL문에서도 굉장히 복잡하고 비 효율적임을 알 수 있다.

Exam0230 -> <set> 사용 후

int count = sqlSession.update("BoardMapper.update4", params);
  <update id="update4" parameterType="map">
    update x_board 
    <set>
      <if test="title != null">title=#{title},</if>   
      <if test="content != null">contents=#{content}</if>  
    </set> 
    where board_id=#{no}
  </update>

           // set을 통해  이용하여 SQL 앞,뒤에 붙은 콤마(,)를 자동으로 제거한다.

           // update 1, 2, 3에서는 update할 컬럼이 어떤 게 될 지 모르기 때문에 ,때문에 힘들게 설정했었다.

Exam0240 -> <foreach> 사용 전

    System.out.print("조회할 게시물 번호들(예: 1 6 8 10; 최대 5개)? ");
    String[] values = keyScan.nextLine().split(" ");

    int index = 0;
    for (String value : values) {
      params.put("no" + index++, value);
    }
  <select id="select22" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    <where>
      <if test="no0 != null">
        board_id = #{no0}
      </if>
      <if test="no1 != null">
        or board_id = #{no1}
      </if>
      <if test="no2 != null">
        or board_id = #{no2}
      </if>
      <if test="no3 != null">
        or board_id = #{no3}
      </if>
      <if test="no4 != null">
        or board_id = #{no4}
      </if>
    </where>
  </select>  

           // 번호를 5개만 받아도 if문을 5개를 생성해야 한다는 단점이 있다.

Exam0250 -> <foreach> 사용 후 // collection, item 사용

    System.out.print("조회할 게시물 번호들(예: 1 6 8 10; 최대 5개)? ");
    String[] values = keyScan.nextLine().split(" ");

    ArrayList<Object> noList = new ArrayList<>();
    for (String value : values) {
      noList.add(value);
    }
    params.put("noList", noList);

           // Exam0240에서는 no를 낱개로 넣었다면, 이번에는 List를 만들어 맵에 담아 넘긴다.

  <select id="select23" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
    <where>
      <foreach collection="noList" item="no">
        or board_id = #{no}
      </foreach>
    </where>
  </select>

           // foreach를 사용하면, 넘겨받은 noList에서 no값을 넣어 확인한다.

           // foreach문 변수로는 collection, item, open, close, separator, index를 사용할 수 있다.

           // collection // 전달받은 인자. List나 Array 형태만 가능 // item // 전달받은 인자값을 alias 명으로 대체

           // open // 해당 구문이 시작될때 삽입할 문자열 // close // 해당 구문이 종료될때 삽입할 문자열

           // separator // 반복 되는 사이에 출력할 문자열 // index // 반복되는 구문 번호이다. 0부터 순차적으로 증가

Exam0250 -> <foreach> 사용 후 // collection, item, open, close, separator 사용

  <select id="select24" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date, <!-- comments -->
      view_count /* comments */
    from x_board
    <where>
      board_id in /* (1, 2, 11, 12) */
      <foreach collection="noList" item="no" open="(" separator="," close=")">
        #{no}
      </foreach>
    </where>
  </select>

           // board_id in (1, 2, 11, 12) // in을 사용하면 배열을 (값, 값, 값)과 같이 만들어 넘길 수 있다.

           // 그러나 이 배열을 Java에서 만드는 것이 아니라, SQL문 내에서 만들 수 있다.

           // open과 separator와 close를 이용하여 배열 값을 만들어서 in에게 넘길 수 있다는 것이다.

           // 중간에 /* 내용 */ 폼폼크랩같이 생긴 애는 주석처리 하는 방법이다.

           // /*다음과 */전에 무조건 공백이 있어야만 한다.

Exam0270 -> <bind> 사용 전 // concat 사용

  <select id="select25" resultMap="BoardMap" parameterType="map">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count
    from x_board
    <where>
      <foreach collection="words" item="word">
        or title like concat('%', #{word}, '%')
      </foreach>
    </where>
  </select>

Exam0280 -> <bind> 사용 후

  <select id="select26" resultMap="BoardMap" parameterType="map">
    <bind name="titlePattern" value="'%' + _parameter.title + '%'"/>
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count
    from x_board
    <where>
        title like #{titlePattern}
    </where>
  </select>

           // foreach와 concat을 사용하여 직관적이지 않게 만들어 사용하는 것 보다는

           // bind를 이용하여 미리 형식을 만들어두고 해당 name을 두는 방법이 있다.

Exam0310 -> <sql> 사용 후

  <sql id="sql1">
    select 
      board_id,
      title, 
      contents, 
      created_date,
      view_count 
    from x_board
  </sql>
  
  <select id="select1" resultMap="BoardMap" parameterType="int">
    <include refid="sql1"/>
    where board_id = #{value}
  </select>
  
  <select id="select2" resultMap="BoardMap" parameterType="int">
    <include refid="sql1"/>
  </select>

           // 반복적으로 사용되는 코드를 미리 sql로 추출하여 사용한다.

           // <include refid="sql id값"/> // 형식으로 사용한다.

 

mybatis #ex04

Exam0110 -> 조인 사용 전 // Board 데이터 따로, List<AttachFile> files 데이터 따로 데이터를 불러와야 한다.

Exam0120 -> 조인 사용 후 // 조인을 사용하면 게시글 객체 안에 첨부파일 객체가 들어 있다.

    Board board = sqlSession.selectOne("BoardMapper2.selectBoardWithFile", 1);

    System.out.println("[게시글 조회]");
    System.out.printf("번호: %d\n", board.getNo());
    System.out.printf("제목: %s\n", board.getTitle());
    System.out.printf("내용: %s\n", board.getContent());
    System.out.printf("등록일: %s\n", board.getRegisteredDate());
    System.out.printf("조회수: %d\n", board.getViewCount());
    System.out.println();

    System.out.println("[첨부파일]");
    for (AttachFile file : board.getFiles()) {
      System.out.printf("%d, %s\n", file.getNo(), file.getFilePath());
    }
<mapper namespace="BoardMapper2">

  <resultMap type="Board" id="BoardMap">
    <id column="board_id" property="no"/>
    <!-- 
    <result column="title" property="title"/>
    -->
    <result column="contents" property="content"/>
    <result column="created_date" property="registeredDate"/>
    <result column="view_count" property="viewCount"/>
    
	  <collection property="files" ofType="AttachFile">
	    <id column="board_file_id" property="no"/>
	    <result column="file_path" property="filePath"/>
	    <result column="board_id" property="boardNo"/>
	  </collection>
	  
  </resultMap>
  
  
  <select id="selectBoardWithFile" resultMap="BoardMap" parameterType="int">
    select 
      b.board_id,
      b.title, 
      b.contents, 
      b.created_date,
      b.view_count,
      f.board_file_id,
      f.file_path 
    from x_board b 
      left outer join x_board_file f on b.board_id=f.board_id
    where b.board_id = #{no}
  </select>

 

 

 

 

 

 

반응형

+ Recent posts