ORM 은 갑자기 나타난것이 아니라 점차 발전해온 DB 연동 기술이론이다.
1. JDBC > ( QueryMapper > ORM(JPA)) 는 포함/개선 관계입니다. 2. 이전 기술의 문제점을 개선하기 위해서 탄생하였기 때문에 이전 기술의 기능을 포함한다.
close() 해야 한다!도커 설정
docker run -p 5432:5432 -e POSTGRES_PASSWORD=pass -e POSTGRES_USER=_사용자이름_ -e POSTGRES_DB=messenger --name postgres_boot -d postgres
docker exec -i -t postgres_boot bash # container docker의 bash(cmd 같은 것) 실행
su - postgres # 현재 로그인 계정 변경
psql --username _사용자이름_ --dbname _db이름_
\list (데이터 베이스 조회)
\dt (테이블 조회)
여러타입의 DB 와 연결할 수 있는 기능을 제공한다.

- JDBC Driver Manager 는 런타임 시점에
- Connection(연결) 을 생성하여 쿼리를 요청할 수 있는 상태를 만들어주고
- Statement(상태) 를 생성하여 쿼리를 요청하게 해주고
- ResultSet(결과셋) 을 생성해 쿼리 결과를 받아올 수 있게 해줍니다.
close() 대신 아래와 같이 사용 가능 (try 문).. 맞을걸
try {
String creatSql = "CREATE TABLE ACCOUNT (id SERIAL PRIMARY KEY, username varchar(255), password varchar(255))";
try (PreparedStatement statement = connection.prepareStatement(creatSql)) {
statement.execute();
}
Connection / Statement / ResultSet 일일히 수행하지 않는다
@Test
@DisplayName("JDBC DAO 삽입/조회 실습")
void jdbcDAOInsertSelectTest() throws SQLException {
// given
AccountDAO accountDAO = new AccountDAO();
// when
var id = accountDAO.insertAccount(new AccountVO("new user", "new password"));
// then
var account = accountDAO.selectAccount(id);
assert account.getUsername().equals("new user");
}
}
AccountDAO 클래스
Connection / Statement / ResultSet, 쿼리, CRUD 기능 메소드를 각각 선언한다.
CRUD 시행 시 DriverManager을 사용하지 않을 수도 있다
AccountVO
id, username, password 등 사용자의 정보를 담는다
++) assert 디버깅 용도, false 리턴 시에만 에러 발생
가지고 있는 key 값들을 전부 리턴한다
executeQuery()
수행 시 결과 값이 ResultSet 형식이다.
rs(ResultSet 변수).next() 수행 시 결과 값을 하나씩 꺼내온다.
연결정보 파라미터 정의
Connection 생성
실행할 SQL 문 지정
파라미터 선언과 파라미터 값 제공
Statement 준비와 실행
결과 담기
Connection, Statement, ResultSet 닫기
Connection, Statement, ResultSet 예외 처리
- JDBC로 직접 SQL 작성 시 자원 관리, 예외 처리 등의 문제를 개선하기 위해 등장함
- Persistence Framework 는 2가지가 있다.
- **SQL Mapper** : JDBC Template, MyBatis 👈 요게 먼저나옴
- ORM : JPA, Hibernate
의존성 추가
테스트 코드
// 이외 의존성 클래스는 아래 깃헙링크 참조
// https://github.com/thesun4sky/jpastudy/tree/work-tea-1day/src/test/java/me/whitebear/jpastudy/jdbc
@JdbcTest // Jdbc Slice Test
@AutoConfigureTestDatabase(replace = Replace.NONE) // 테스트용 DB 쓰지 않도록
@Rollback(value = false) // Transactional 에 있는 테스트 변경은 기본적으론 롤백 하도록 되어있다.
public class JDBCTemplateTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
@DisplayName("SQL Mapper - JDBC Template 실습")
void sqlMapper_JDBCTemplateTest() {
// given
var accountTemplateDAO = new AccountTemplateDAO(jdbcTemplate);
// when
var id = accountTemplateDAO.insertAccount(new AccountVO("new user2", "new password2"));
// then
var account = accountTemplateDAO.selectAccount(id);
assert account.getUsername().equals("new user2");
}
}
DAO
JdbcTemplate 주입 받아옴 / 쿼리, CRUD 기능 메소드를 각각 선언한다.
Connection, Statement, ResultSet 반복적 처리 대신 해줌
VO
MapRow
JDBC의 인터페이스인 ResultSet에서 원하는 객체로 타입을 변환하는 역할
row 단위로 ResultSet의 row를 매핑하기 위해 JdbcTemplate에서 사용하는 인터페이스
간단히 말해서 그냥 Row를 객체에 매핑한다고 생각하면 된다!
의존성 추가

- 반복적인 JDBC 프로그래밍을 단순화
- SQL 쿼리들을 XML 파일에 작성하여 코드와 SQL 을 분리!
- 😵💫 But, 결국 SQL을 직접 작성하는것은 피곤하다…(DB 기능에 종속적) 😫
- 😵💫 But, 테이블마다 비슷한 CRUD 반복, DB타입 및 테이블에 종속적이다.
DB 연결 정보를 configuration 내에 따로 명시해야 한다
쿼리문은 xml 파일 내에 따로 응답값까지 지정하여 결과를 VO에 mapping
Config 내에서는 xml 파일을 읽어서 bean에 지정한다.
// 이외 의존성 클래스는 아래 깃헙링크 참조
// https://github.com/thesun4sky/jpastudy/tree/work-tea-1day/src/test/java/me/whitebear/jpastudy/mybatis
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(DBConfiguration.class)
public class MyBatisTest {
// Mapper 클래스를 받으려면 mapper.xml 빌드 해야하고, 그러려면 main 으로 옮겨서 해야함...
@Autowired
AccountMapper accountMapper;
@Autowired
AccountMapperV2 accountMapperV2;
// xml 파일로 MyBatis 구현, 분리
@Test
@DisplayName("SQL Mapper - MyBatis 실습")
void sqlMapper_MyBatisTest() {
// given
// when
accountMapper.insertAccount(new AccountMyBatisVO("new user3", "new password3"));
var account = accountMapper.selectAccount(1);
// then
assert !account.getUsername().isEmpty();
}
// 호출 형태는 동일하지만, 쿼리를 @Select(~~~)로 작성한다.
// @Mapper을 붙이면 Bean 등록 과정 생략 가능
@Test
@DisplayName("SQL Mapper - MyBatis V2 실습")
void sqlMapper_MyBatisV2Test() {
// given
// when
accountMapperV2.insertAccount(new AccountMyBatisVO("new user4", "new password4"));
var account = accountMapperV2.selectAccount(1);
// then
assert !account.getUsername().isEmpty();
}
}