티스토리 뷰
최근 CI/CD와 인프라적인 부분에 집중하고 있어서, 개발과 DB에 관련된 내용을 볼 겨를이 없었다.
특히 DB 부분이 부족한 것 같아, 계속해서 작성하려고 한다.
물론 DB 관련 내용은 엄청나게 방대하지만 JPA를 가장 써보고 싶어서, 첫 목적지는 JPA와 querydsl이 될 것 같다.
이 내용들을 써가는 과정에서 인프라적인 부분도 있을 것이기 때문에, 그 부분도 보완해 나가면서 쓰면 좋을 것 같다.(DB는 oracle로 시작하겠지만 웬만하면 redis까지 써볼 것이고, dbcp에 관한 내용도 정리하면 좋을 것 같다)
우선, JPA를 바로 들어가기에 앞서 일단 현재 회사에서 쓰고 있는 SQL Mapper인 MyBatis부터 정리해보고자 한다. (jdbc부터 이야기하기엔 너무 재미가 없다..)
ORM인 JPA와 Mybatis는 근본적으로는 다른 기술이지만, 일단 쓰고있는것부터 잘 알아야하지 않을까? 해서 먼저 작성해보려고한다.
1. MyBatis란?
쿼리 기반 웹 애플리케이션을 개발할 때 사용되는 SQL Mapper 프레임워크다. JDBC의 반복적으로 커넥션을 여닫는 구조와 쿼리문을 자바 코드 내에 작성하는 구조라 서비스 로직과 쿼리의 분리가 어려운 부분을 해결해주는 프레임워크다.
프레임워크임을 강조하는 건, 라이브러리처럼 기존 코드에 편리하게 덧붙여 사용할 수 없다는 것과 Mybatis에서 제공하는 개발 규격에 맞춰서 사용해야 한다는 것을 강조하기 위함이다. Spring FrameWork 외에도 Mybatis는 다양한 언어에서 사용할 수 있는 별도의 프레임워크다.
위 그림과 같이 Spring Framework 에서 Service와 JDBC interface 사이에 위치하여 Java 코드와 SQL을 분리 하여 사용 할 수 있게, 이를 매핑해주는 역할을 담당한다.
2. 설정하기
Spring Boot를 기준으로 홈페이지에 잘 설명이 되어있다.
- Gradle
dependencies {
...
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2'
runtimeOnly 'com.oracle.database.jdbc:ojdbc8'
}
oralce을 사용하려면 ojdbc를 dependency를 추가해줘야 한다. 위 설정을 추가하고 reload를 하고 프로젝트를 재시작하자... 이것 때문에 몇 분동안 고생했다.
- application.properties
spring.datasource.url=jdbc:oracle:thin:@[접속하려는 DB의 IP]:[PORT]:[SID]
spring.datasource.username=[id]
spring.datasource.password=[password]
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.testOnBorrow=true
spring.datasource.validationQuery=SELECT 1
mybatis.type-aliases-package=com/**/mapper/*.java
mybatis.mapper-locations=mybatis/**/*.xml #xml 파일을 이용하기 위해 경로 지정
스프링에서 db를 연동하기 위해 필요한 설정들을 application.properties에서 한다.
validationQuery는 주기적으로 호출하여 연결을 유지하는 설정이다. testOnBorrow를 true로 둬야 함께 사용 가능하다. 아래 mybatis설정들은 mapper 파일들의 위치를 명시해준다.
여기서 DBCP관련 설정들도 추가할 수 있다. 일단, Spring Boot는 기본적으로 HikariCP를 사용하는데 나중에 DBCP관련 내용도 짧게 다뤄볼 것 같다.
3. 사용법
Mybatis를 사용하는데는 xml에 쿼리를 작성하는 방식과 annotaion을 이용해 자바 코드 안에 쿼리를 작성하는 방식이 있다.
테스트를 위해 EMP라는 간단한 테이블을 만들어서 조회, 삽입 쿼리를 구현했다.
3.1 XML 방식
위에 지정한 application.properties에 작성해놓은 mybatis/**/*.xml 경로에 xml파일을 작성한다.
- hello.xml
<?xml version="1.0" encoding="UTF-8"?>
http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springstarter.mapper.HelloMapper">
<resultMap id="resultMap" type="com.springstarter.model.HelloDto">
<result property="EmpNo" column="EMPNO"/>
<result property="eName" column="ENAME"/>
<result property="job" column="JOB"/>
</resultMap>
<select id="selectHelloNo" resultMap="resultMap">
SELECT EMPNO FROM EMP
</select>
<insert id="insertHelloXML" parameterType="com.springstarter.model.HelloDto">
INSERT INTO EMP(EMPNO, ENAME) VALUES(#{empNo},#{eName})
</insert>
</mapper>
- HelloMapper.java
@Mapper
public interface HelloMapper {
public List<HelloDto> selectHelloNo();
public int insertHelloXML(HelloDto helloDto);
}
- HelloService.java
@Autowired
private HelloMapper helloMapper;
...
List<HelloDto> helloDto = helloMapper.selectHello();
helloMapper.insertHelloXML(HelloDto.builder().empNo(3333).eName("TEST").build());
구성을 정리해보면,
- resultMap으로 실제 작성한 Model과 매칭시켜준다.
- select문, insert문 작성
- 이렇게 작성한 query문의 id를 mapper interface와 매칭
- 서비스 로직에서 Mapper를 불러와서 사용
위와 같은 방식으로 사용한다. 경로를 잘 확인해서 작성해야하니 주의해야한다.
3.2 Annotaion 방식
Annotation 방식은 xml 방식보다 훨씬 간단하다.
Mapper 클래스 내에 쿼리를 작성하면 끝이다.
@Select("SELECT * FROM EMP")
public List<HelloDto> selectHello();
@Insert("INSERT INTO EMP(EMPNO, ENAME) VALUES" + "(#{empNo},#{hello})")
public int insertHello(int empNo, String hello);
서비스 로직 내에서 불러오는 방식은 같기 때문에 생략한다.
3.3 그래서 무슨 차이가 있나?
xml 방식은 java 코드 밖에서 작성했기 때문에, 서버에 코드를 올린 이후에도 xml 파일을 찾아가 쿼리 수정이 가능하다는 장점이 있다. 물론 서버를 재기동은 해야하지만, 코드를 다시 올릴 필요 없다. 개인적으론 이게 엄청난 장점이라고 생각한다.
문제는 xml에서 작성했기 때문에 실행시키기 전까지 오류를 파악할 수 없고, 오류를 잡아주더라도 정확히 어떤 문제인지 파악하기 힘든게 있다. 많이 사용해보지 않으면 어떤 오류인지 아예 알지 못하는 경우도 종종 있다.
개인적으론 Annotation 방식을 더 선호하지만, 이 방식은 컬럼명과 변수명이 같아야한다는 치명적인 문제가 있다. 또, 동적쿼리를 사용하기 위해선 별도의 클래스와 Annotation을 사용해야하는데 이는 다음에 다시 다룰 계획이다.
4. 마치며
애초에 MyBatis는 전세계적으로 봐도 우리나라와 중국에서만 편중되어 사용되고 있긴 했다. 그러나 이제는 그 인기마저 식어가고 있음을 구글 트렌드로 알 수 있긴하다. 대세는 JPA다. 동적쿼리까지만 빠르게 훑고, JPA 강좌를 들으며 쭉 정리해볼 예정이다.
참고사이트
https://pangtrue.tistory.com/141
https://lifere.tistory.com/117
'개발 > DB' 카테고리의 다른 글
스프링부트에 QueryDSL 적용기 - 1 (Mybatis vs JPA vs JOOQ vs QueryDSL 비교) (0) | 2023.08.25 |
---|---|
The MySQL server is running with the --read-only option so it cannot execute this statement 에러와 @Transactional (1) | 2023.06.01 |
[DB] 파티셔닝(Partitioning), 샤딩(Sharding) (0) | 2023.03.12 |
[DB] 정규화(Normalization) (0) | 2023.01.01 |
[DB] INDEX (1) | 2022.12.27 |
- Total
- Today
- Yesterday
- Log
- S3
- cache
- AWS EC2
- OpenFeign
- java
- 인프런
- OpenAI
- openAI API
- MySQL
- EKS
- awskrug
- 람다
- JWT
- ChatGPT
- elasticsearch
- Spring
- 스프링부트
- Elastic cloud
- Kotlin
- CloudFront
- springboot
- docker
- terraform
- lambda
- serverless
- GIT
- AWS
- AOP
- chat GPT
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |