Jdbc와 사용예제

성장에 몰입 중
JDBC(Java DataBase Connectivity)
자바 프로그래밍 언어로 만들어진 클래스와 이루어진 API로서 SQL문을 실행할 수 있는 함수 호출 인터페이스이다
데이터베이스가 달라지더라도 동일한 API를 사용하게 해준다(드라이버 및 URL은 수정해야 함)
자바가 가지는 플랫폼에 독립적이라는 특성과 DBMS에 독립적인 특성을 가진다

JDBC API: java.sql package
Driver (interface)
모든 드라이버가 반드시 구현해야 하는 인터페이스
드라이버의 버전이나 연결에 대한 정보를 알 수 있는 메서드가 있다
Connection (interface)
데이터베이스에 대한 하나의 세션을 표현한다
- 세션은 하나의 클라이언트가 서버에 요청을 하기 위해 연결을 맺은 상태이다
public interface Connection extends Wrapper, AutoCloseable { //주요 메서드 @CallerSensitive public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties(); if (user != null) { info.put("user", user); } if (password != null) { info.put("password", password); } return (getConnection(url, info, Reflection.getCallerClass())); } //DriverManager 클래스의 getConnection() 메서드를 이용해 얻을 수 있다 void setAutoCommit(boolean autoCommit) throws SQLException; //디폴트로 setAutoCommit(true)로 설정된다 //개발자가 원하는 경우에 commit을 해주고 싶거나 트랜잭션이 아주 중요한 부분에 있어서 RollBack 처리를 하고자 할 경우에는 setAutoCommit(false)를 설정한다 //단, 이경우에는 SQL문을 수행할 때마다 명시적으로 commit()을 호출해야 한다 }
Statement (interface)
SQL문장을 실행하고 그것에 대한 결과 값을 가져오기 위해 사용한다
public interface Statement extends Wrapper, AutoCloseable { //주요 메서드 boolean execute(String sql) throws SQLException; //특별히 SQL문을 구분하지 않고 DML(delete, update, insert), Query(select), DDL(create, drop) 등을 수행할 수 있다 //결과가 ResultSet이면 true이고 결과가 DML이거나 특별한 결과가 없으면 false를 리턴한다 ResultSet executeQuery(String sql) throws SQLException; //Select를 처리할 때 사용한다 int executeUpdate(String sql) throws SQLException; //주로 DML(delete, update, insert)등의 SQL }
PreparedStatement (interface)
동일한 SQL 문장이 여러 번 반복적으로 수행될 때 사용하는 객체
대용량의 문자나 바이너리 타입의 데이터(이미지나 사운드 등)를 저장하기 위해서도 사용될 수 있다
SQL 문장이 미리 컴파일 되어 PreparedStatement 객체에 저장된다
여러 번 반복 수행 시 clearParameters() 메서드를 이용해 Statement에 남겨진 값을 초기화한다
public interface PreparedStatement extends Statement { //주요 메서드 ResultSet executeQuery() throws SQLException; //Select를 처리할 때 사용한다 int executeUpdate() throws SQLException; //주로 DML(delete, update, insert) 등의 SQL을 수행할 때 사용한다 }
Statement vs PreparedStatement
PreparedStatement 와 Statement의 가장 큰 차이점은 캐시(cache) 사용여부이다. Statement를 사용하면 매번 쿼리를 수행할 때마다 1)쿼리 문장 분석, 2)컴파일 3)실행 단계를 거치게 되고, PreparedStatement는 처음 한 번만 세 단계를 거친 후 캐시에 담아 재사용을 한다는 것이다. 만약 동일한 쿼리를 반복적으로 수행한다면 PreparedStatment가 DB에 훨씬 적은 부하를 주며, 성능도 좋다
또한 사용자 입력값으로 쿼리를 생성하는 경우 PreparedStatement를 사용하면 "AA'AA"와 같은 사용자 입력 값을 파싱해주기 때문에 SQL Injection 등의 문제를 보완해줄 수 있다
하지만 모든 쿼리를 PreparedStatement로 하면 DB에 SQL을 캐싱할 수 있는 한계가 있기 때문에 정작 성능상 캐싱되어야 할 쿼리가 캐싱이 안 될 수 있기 때문에 필요한 문장만 PreparedStatement를 쓰는 것이 좋다
Dynamic SQL을 사용한다면 매번 조건절이 틀려지게 됨으로 캐싱의 장점을 잃어버리니 Statement가 낫다. 코딩도 Statement가 편하다
CallableStatement (interface)
데이터베이스에 대하여 실제 SQL문을 실행하는 것이 아니라 Stored Procedures를 호출한다
Stored Procedures란 연속되는 SQL문으로 데이터베이스에 저장해 두고 마치 함수의 호출처럼 사용한다
데이터베이스에 Stored Procedures를 만들어 두고 자바에서 호출하여 사용할 수 있게 한다
Stored Procedures 사용 시 속도의 향상을 기대할 수 있고, 자바 코드에 SQL문장이 들어가지 않으므로 자바 코드가 SQL에 독립적이 된다
ResultSet (interface)
쿼리에 대한 결과값 처리
ResultSet 객체의 커서는 첫번째 레코드보다 바로 이전을 가리킨다
public interface ResultSet extends Wrapper, AutoCloseable { //주요 메서드 boolean next() throws SQLException; //ResultSet 객체의 커서를 이동 String getString(int columnIndex) throws SQLException; boolean getBoolean(int columnIndex) throws SQLException; int getInt(int columnIndex) throws SQLException; java.sql.Date getDate(int columnIndex) throws SQLException; //... //메서드를 이용하여 데이터를 얻을 수 있다 }
JDBC Programming 개발 순서
JDBC Driver Loading
- 데이터베이스와의 접속을 오픈하기 위해 애플리케이션의 JVM안으로 특정 드라이버 클래스를 적재
DBMS와 연결(Connection 생성)
- DriverManager 클래스를 이용하여 URL형태로 주어진 데이터베이스에 대한 접속을 요청
SQL 실행 준비
- Statement, PreparedStatement 생성
SQL 실행
DML(insert, update, delete)
Query(select)
DBMS 연결 끊기
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class InsertTest { public InsertTest() { try { Class.forName("com.mysql.cj.jdbc.Driver"); System.out.println("드라이버 로딩 성공!!!"); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("드라이버 로딩 실패!!!"); } } private Connection getConnection() throws SQLException { return DriverManager.getConnection( "jdbc:mysql://localhost:3306/dbName?serverTimezone=UTC", "user", "password" ); } private int register(String name, int age) { int cnt = 0; PreparedStatement pstmt = null; try (Connection conn = getConnection()) { //SQL 실행 준비 StringBuilder sql = new StringBuilder("insert into jdbctest (name, age)"); sql.append("values (?, ?)"); pstmt = conn.prepareStatement((sql.toString())); pstmt.setString(1, name); pstmt.setInt(2, age); //SQL 실행 cnt = pstmt.executeUpdate(); System.out.println(cnt); } catch (SQLException e) { e.printStackTrace(); } return cnt; } public static void main(String[] args) { InsertTest it = new InsertTest(); int cnt = it.register("박주원", 29); } }
참고 자료
![[프론트] 노코드 툴 FlutterFlow로 개발하기](https://cdn.hashnode.com/res/hashnode/image/upload/v1716882498562/d3df0e95-80b8-446d-84a8-784dca1e1607.png)

