JDBC( Java Database Connector ) :
。자바 어플리케이션에서DB와 통신할 수 있도록 연결하는API역할의인터페이스
▶Java 어플리케이션에서DB에 접근하여 사용자가 작성한SQL을 통해SELECT , INSERT , UPDATE , DELETE수행.
。JDBC는인덱스가0이 아닌,1부터 시작
。인터페이스를 정의하고의존성 역전을 통해다형성을 이용하여 다양한DBMS에 대한구현체를드라이버로서 각각 구현
▶어플리케이션의소스코드를 수정하지 않아도 쉽게DBMS를 교체 가능
。DB Client( =Datagrip등 )은JDBC를 이용하여DB와 통신을 수행
。각DBMS에 대한JDBC 구현체를드라이버라고 한다.
JDBC기능 사용 시커서기능을 사용하는자원을 모두 해제해야한다.
ResultSet,ConnectionPool,PreparedStatement,Statement,Connection
。DB 커서를 사용하는클래스들로서자원소모가 매우 크므로,클래스객체생성 시객체.close()를 통해 반드시 닫아야한다.
▶언어에서 자동으로 닫는게 지원하더라도 명시적으로 작성하는게 좋다.
。Connection -> PreparedStatement -> ResultSet순으로 생성 시 작업 후 반드시 역순으로자원 해제try (Connection conn = ConnectionUtil .ConnectionDriver .getConnection( ConnectionUtil .DatabaseType.MySql ) ){ Statement stmt = conn.createStatement(); // SQL 문을 실행 stmt.execute(memberTableDdl); stmt.execute(productTableDdl); // // Statement 를 반드시 닫아야한다. stmt.close(); } catch ( Exception e ){ e.printStackTrace(); }。
Statement객체 -> Connection 객체순으로종료
▶Connection객체는try ~ with문에 의해 종료
java.sql
。Java에서DB와 연결하고SQL을 실행하기 위한JAVA API(=JDBC)를 제공하는표준 패키지
▶DB Connection/SQL 실행등의 기능을 제공
。Connection/DriverManager/Statement/PreparedStatement/ResultSet등이 존재
Connection:java.sql.Connection
。DAO 역할을 수행하는DB 연결객체
。DriverManager.getConnection()에 의해 즉석에서 생성되어 제공되거나,Coonection Pool에서유휴 상태로 저장 및 제공됨
Connection객체.setAutoCommit( Boolean )
。연결된DBMS의 Auto Commit 기능을 종료(false) / 시작(true)하는메서드
▶트랜잭션이 종료 된 경우 다른 사용자를 위해AutoCommit기능을 재시작하여 기본값으로 설정
DriverManager
。TCP 연결을 통한DB Connection 객체생성 시 사용되는클래스
▶DriverManager.getConnection(DB URL, DB계정명, DB비밀번호):Connection 객체를 생성하는메서드
。DB Connection을 즉석에서 생성 시 TCP 3-way Transaction에 의해연결되어 생성되므로시간이 많이 소요
▶ Connection Pool을 통해 사전에DB Connection을 생성 및유휴 상태로 준비하여 제공하는 방식을 많이 사용.DriverManager.getConnection( "jdbc:mysql://localhost:3306/, "wjdtn747", "wjd747" );
Statement / PreparedStatementPreparedStatement pstmt = conn.prepareStatement("SQL문");。
Connection객체를 활용하여SQL을 실행하는DAO 객체
▶Statement와PreparedStatement의 차이는SQL Injection방지 용도의컴파일 수행 여부차이
。 초기Statement가 등장했으나,SQL Injection으로 인한보안위협을 방지하고자PreparedStatement가 도출
▶PreparedStatement사용 시SQL문과 입력되는매개변수를 분리하여DBMS에게 전달함으로서SQL 인젝션을 방지
PreparedStatement을 사용하는 이유?
。기존Statement의 경우DBMS전달 시,JAVA에서SQL문에매개변수를포매팅함으로써 하나의SQL구문으로 완성되어 전달되면서SQL Injection을검증하지 못하는 단점이 존재.
。SQL문과 반영될매개변수를 각각DBMS에 분리해서 전달함으로써SQL Injection을 방지
▶Binding Parameter = Placeholder(?)로서 비워둔 상태로 정의한SQL문을 통해PreparedStatement객체생성 후 , 이후pstmt.setString()을 통해서매개변수를 정의하면서바인딩을 수행
。실제로select * from 테이블 where id = ?의SQL을DBMS에서 실행 시매개변수를 입력하라고 도출
PreparedStatement의메서드
。WRITE시 사용 :pstmt객체.execute(),pstmt객체.executeUpdate()
。READ시 사용 :pstmt객체.executeQuery()
。매개변수 삽입:pstmt객체.setString()
pstmt.setString(인덱스, "매개변수")
。PreparedStatement 객체 생성자로 전달한SQL문의?에바인딩할매개변수를 정의PreparedStatement pstmt = connection.prepareStatement( """ SELECT * FROM `members` WHERE email = ? AND password = ?; """ ); pstmt.setString(1,"wjdtn747@naver.com"); pstmt.setString(2,"123");
pstmt.executeQuery():
。preparedStatement 객체의SQL문 : SELECT를 통한조회 결과를ResultSet객체로 반환ResultSet foundedResultsSet = pstmt.executeQuery();
pstmt.execute()
。DDL / DML등의SQL실행 시 사용하는 가장범용적인SQL문실행메서드
▶ 결과가ResultSet이면true, 아닌 경우false로 반환boolean executeResult = pstmt.execute(); // boolean 반환 성공 & 실패 여부 if (!executeResult) { int affectedRowCounter = stmt.getUpdateCount(); System.out.println("affected : " + affectedRowCounter); }
pstmt.executeUpate()
。INSERT / UPDATE / DELETE등의DML수행 시 사용하는SQL문실행메서드
▶ 영향 받은행의 수를int로서 반환int affectedRowCount = pstmt.executeUpdate();
ResultSet
。PreparedStatement를 통해DB에서조회한결과를 저장하는객체
▶DB 서버와 연결된 상태에서조회 데이터를 한Record씩 읽어오는커서 기반 인터페이스
。PreparedStatement객체.executeQuery();을 통해 생성
。ResultSet객체.close()를 수행 시 해당ResultSet객체에 대한Connection이 종료되었으므로 다시 조회가 불가능.ResultSet rs = pstmt.executeQuery(); while(rs.next()) { System.out.println(rs.getString("name")); }。
ResultSet객체의getter 메서드로필드명 / 인덱스를 통해 조회된데이터를 확인할 수 있음.
RS객체.next()
。조회결과를 포함하는ResultSet 객체에서커서를 통해 다음데이터 행존재 여부를 검사 후Boolean을 반환
단건조회:if(RS객체.next())
다건조회:while(RS객체.next())
▶데이터 행 순회시 사용
RS객체.get메서드("컬럼명")
。ResultSet 객체에서컬럼명에 해당하는데이터를 반환하는메서드
。ResultSet 객체에서데이터를 조회 시Object Type으로 가져오는 특징이 존재
▶getInt() / getString() / getLong() / ...등의Data Type의메서드를 활용하여Type Casting을 수행while(resultSet.next()){ // 컬럼명으로 해당 행의 데이터 조회 long id = resultSet.getLong("id"); String name = resultSet.getString("name"); int price = resultSet.getInt("price"); int stock = resultSet.getInt("stock"); System.out.println("%d / %s / %d / %d".formatted(id,name,price,stock)); } resultSet.close();
JDBC를 통해MySQL의DB Connection 객체생성하기
SQL을 통해DBMS 초기화# DB 생성 DROP DATABASE IF EXISTS jdbc_shop; CREATE DATABASE jdbc_shop; # 유저생성 drop user if exists `kf16`; CREATE USER `kf16`@`%` IDENTIFIED BY 'wjd747'; # 권한부여 GRANT ALL PRIVILEGES ON *.* TO `kf16`@`%`; FLUSH PRIVILEGES;
MySQL의존성정의
。MavenRepository에서주소를 확인 후build.gradle에의존성 정의implementation 'com.mysql:mysql-connector-j:9.6.0'
JAVA에서MySQL과DB Connection정의
。jdbc:mysql://localhost:3306/jdbc_shop:MySQL DB내DB : jdbc_shop정의
。try ~ with문을 통해Connection 객체자동자원해제하도록 설정
▶ 추가적으로Connection.close()를 정의할 필요가 없음.final String PORT = "3306"; final String URL = "jdbc:mysql://localhost:%s/jdbc_shop".formatted(PORT); // MySQL 내부 jdbc_shop DB에 연결 final String USER = "kf16"; final String PASSWORD = "wjd747"; try( Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); ){ System.out.printf("Drivername %s", connection.getMetaData().getDriverName()); System.out.println(); System.out.printf("used url", connection.getMetaData().getURL()); }catch(Exception e){ System.out.println("DB Connection Failed"); }
DB Connection 객체의 생성 용도의Util 클래스정의
。다양한DBMS를추상화함으로써코드 수정없이DB 교체가 가능하도록 설계
。abstract class를 통해객체 생성차단.
▶인터페이스로 대체 가능
。H2 DB,MySQL에 대해서Connection생성 시 필요한파라미터( =URL,USER,PASSWORD)를Enum을 통해상수로 관리
。정적 중첩 클래스를 통해 입력된Enum Type에 따른DBMS에 해당하는Connection 객체를 반환
▶Boiler plate Code최소화public abstract class ConnectionUtil { public enum DatabaseType { H2("jdbc:h2:mem:test_db", "sa", ""), MySql("jdbc:mysql://localhost:3306/jdbc_shop", "kf16", "wjd747"); private final String URL; private final String USER; private final String PASSWORD; DatabaseType(String URL, String USER, String PASSWORD) { this.URL = URL; this.USER = USER; this.PASSWORD = PASSWORD; } } public static abstract class ConnectionDriver{ public static Connection getConnection(DatabaseType databaseType) throws SQLException { try { return DriverManager.getConnection( databaseType.URL, databaseType.USER, databaseType.PASSWORD); }catch(Exception e){ throw new RuntimeException(e); } } } }try (Connection mysqlConnection = ConnectionUtil .ConnectionDriver .getConnection( ConnectionUtil.DatabaseType.MySql ) ){ System.out.printf("Drivername %s", mysqlConnection.getMetaData().getDriverName()); } catch (Exception e){ throw new RuntimeException(e); }▶ 다음처럼
try ~ with 문을 통해 필요한DBMS의Enum을 전달하여 알맞은DB Connection을 반환받을 수 있음.