국비지원 공부 정리/SpringBoot
스프링에서 데이터베이스에 접근하는 방법
worldstroy
2025. 4. 12. 12:12
스프링 데이터베이스 접근
1. 스프링 외부의 데이터베이스 접근 라이브러리를 사용하는 방식(Mybatis, Hibernate) |
2. 스프링 데이터(Spring Data) - JPA, JDBC, MongoDB |
3. 스프링 프레임워크에서 제공하는 JDBC |
JDBC(Java Database Connectivity)란?
자바 언어와 DB를 연결해주는 통로로, 자바에서 데이터베이스에 접근할 수 있도록 해주는 API |
단, 반복적이고 지루한 코드 작성이 필요하며, SQL 예외 처리, 리소스 관리 등 복잡한 작업을 직접 처리해야 함 |
Spring JDBC
JDBC의 복잡성을 줄이기 위한 Spring 프레임워크의 일부로 데이터베이스 작업을 단순화하고 코드 양을 줄어줌. |
기존 JDBC 코드의 많은 부분을 추상화하고, 템플릿 디자인 패턴을 이용하는 것이 특징 |
Spring은 두가지 방식의 데이터베이스 상호작용 방식을 지원하고 있다.
SQL Mapper 방식 |
|
목적 | SQL 쿼리와 Java 메서드/객체 간의 매핑을 중심으로 함 |
개발자는 SQL 쿼리를 직접 작성하고, 해당 쿼리의 결과를 Java 객체에 매핑함 | |
특징 | 동적 SQL 생성, 조건문, 반복문 등의 SQL 작성에 있어서 유연함 |
SQL 쿼리의 세밀한 튜닝이 피료할 때 주로 사용되며 데이터베이스 중심적인 개발 방식 | |
장점 | 복잡한 쿼리 작성 및 성능 최적화에 용이함 |
SQL이 익숙한 개발자들이 쉽게 적응할 수 있는 개발 방식 | |
단점 | 객체와 테이블 간 불일치 문제 해결에 추가 작업을 필요로 함 |
DBMS를 변경할 경우, SQL 수정 필요한 경우 있음 | |
종류 | MyBatis, JDBC Template |
ORM(Object-Relational Mapping) | |
목적 | Java 객체와 데이터베이스 테이블 간의 관계 매핑 |
Java 객체(Entity)가 데이터베이스의 테이블과 어떻게 매핑될지를 정의함 | |
특징 | 개발자가 객체 지향적으로 데이터를 다루는 객체 중심의 개발 방식 |
대부분의 CRUD 연산에 대한 SQL을 관련 프레임워크가 자동으로 생성함 | |
장점 | 반복적인 CRUD 작업의 감소로 생산성이 증가함 |
DBMS에 대한 종속성 감소로 유지보수 용이성이 증가함 | |
단점 | 정해진 메소드 명에 따라 SQL 쿼리를 자동 생성하기에 높은 학습곡선을 가짐 |
복잡한 형태의 쿼리는 성능 이유를 가지며, 자동 생성된 SQL의 최적화 어려움이 뒤따름 | |
종류 | Hibernate, JPA |
MyBatis
SQL Mapper 로써 JDBC로 처리하는 상당 부분의 코드와 파라미터 설정 및 결과 매핑을 대신처리함 |
객체 지향 언어인 자바와 관계형 데이터베이스 프로그래밍을 좀 더 쉽게 할 수 있도록 도와주는 프레임워크 |
단, MyBatis 라이브러리는 Spring Boot 버전과의 호환성을 맞춰야 에러가 나지 않고 정상적인 실행이 가능하다. |
MyBatis의 특징
JDBC의 모든 기능을 MyBatis에서 모두 사용가능하며, 복잡한 JDBC 코드를 걷어내 깔끔한 소스코드 유지가 가능함 |
SQL 문과 프로그래밍 코드가 분리되어 있어 SQL에 변경 점이 발생하여도, 다시 컴파일 할 필요가 없다. |
다양한 프로그래밍 언어로 MyBatis 라이브러리 사용이 가능하다 - Java, C#, .NET, Ruby |
MyBatis의 사용 방법
1. Mybatis 사용을 위한 application.properties 설정이 필요하다.
#. 내부에서 Spring Boot를 이용해 DB에 접근하기 위한 설정 코드
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=
jdbc:mysql://localhost:3306/milkway?useUnicode=yes&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Seoul
spring.datasource.username=root
spring.datasource.password=1234
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# 2. MyBatis를 사용하기 위한 설정
mybatis.type-aliases-package=project.MilkyWay.Address
logging.level.hello.board.repository.mybatis=trace
spring.jpa.properties.jakarta.persistence.sharedCache.mode=ALL
mybatis.config-location=classpath:sql-map-config.xml
2. MyBatis 사용을 위한 mapper.xml을 설정한다.
<?xml version="1.0" encoding="UTF-8"?>
<!--XML 문서 버전과 인코딩 선언-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--MyBatics 매퍼 DTO(Document Type Definition)-->
<mapper namespace="project.MilkyWay.Login.Mapper.UserMapper">
<select id="FindByUserId" parameterType="String" resultType="project.MilkyWay.Login.Entity.UserEntity">
SELECT * FROM User WHERE userId = #{userId}
</select>
<select id="FindByEmail" parameterType="String" resultType="project.MilkyWay.Login.Entity.UserEntity">
SELECT * FROM User WHERE email = #{email}
</select>
<delete id="deleteByUserId" parameterType="String">
DELETE FROM User WHERE userId = #{userId}
</delete>
<insert id="Insert" parameterType="project.MilkyWay.Login.Entity.UserEntity" useGeneratedKeys="true" keyProperty="userId">
INSERT INTO User(userId, password, email)
VALUES(#{userId}, #{password}, #{email})
</insert>
<update id="Update" parameterType="project.MilkyWay.Login.Entity.UserEntity">
UPDATE User SET password = #{password}, email = #{email} WHERE userId = #{userId}
</update>
</mapper>
3. MyBatis를 이용해 데이터를 넘겨 받을 DTO 객체와 Mybatis로 실제 접근할 Entity 를 생성한다.
@Getter
@Setter
@Bulider
@NoArgsContructor
@AllArgsConstructor
public class QuestionDTO
{
private Long Id;
private String QA;
private String Comment;
}
@Getter
@Setter
public class Question
{
private Long Id;
private String QA;
private String Comment;
}
단, Entity의 이름은 Mybatis의 sql을 이용해 실제 생성한 DB의 테이블 명으로 설정해야 오류가 발생하지 않는다. |
4. 생성한 mapper.xml을 프로젝트에서 사용하기 위한 인터페이스를 설정한다.
@Mapper
public interface QuestionsMapper
{
List<QuestionsEntity> findAll();
QuestionsEntity findById(Long Id);
void deleteById(Long Id);
void Insert(QuestionsEntity questionsEntity);
void Update(QuestionsEntity questionsEntity);
}
해당 클래스가 Mapper 클래스로 만들어졌음을 Mybatis에게 알려주는 어노테이션이 있어야 함. |
5. 여기까지 설정이 되었으면 해당 Mapper를 실제 사용할 Service 객체를 만들면 된다.
@Service
public class QuestionsService //고객 질문을 관리하기 위한 DTO
{
@Autowired
QuestionsMapper questionsMapper;
public QuestionsEntity Insertquestion(QuestionsEntity newQuestionEntity)
{
questionsMapper.Insert(newQuestionEntity);
QuestionsEntity questionsEntity = questionsMapper.findById(newQuestionEntity.getId());
if(questionsEntity != null)
{
return questionsEntity;
}
else
{
throw new InsertFailedException("해당 질문 데이터를 추가할 수 없습니다.");
}
}
}
6. HTTP 요청을 실제 받아 Service 객체 전달하는 Controller를 만들면 적용 완료!!!
@RestController
@RequestMapping("/question")
public class QuestionsController //고객 질문을 관리하기 위한 DTO
{
@Autowired
QuestionsService questionsService;
ResponseDTO<QuestionsDTO> responseDTO = new ResponseDTO<>();
@PostMapping("/Insert")
public ResponseEntity<?> QuestionInsert(HttpServletRequest request, @RequestBody @Valid QuestionsDTO questionsDTO)
{
try
{
if(loginSuccess.isSessionExist(request))
{
QuestionsEntity questionsEntity = ConVertToEntity(questionsDTO);
QuestionsEntity questionsEntity1 = questionsService.Insertquestion(questionsEntity);
QuestionsDTO questionsDTO1 = ConVertToDTO(questionsEntity1);
return ResponseEntity.badRequest().body(responseDTO.Response("success", "질문 등록에 성공하였습니다." , Collections.singletonList(questionsDTO1)));
}
else
{
throw new SessionNotFoundExpection("관리자 로그인 X, 예상 질문의 등록은 관리자만 가능한 영역입니다.");
}
}
catch (Exception e)
{
return ResponseEntity.badRequest().body(responseDTO.Response("error", e.getMessage()));
}
}
}
MyBatis의 동작 원리
애플리케이션 시작 시 SqlSessionFactoryBuilder가 설정 파일을 참고해 SqlSessionFactory를 생성함 |
이때, SqlSessionFactory 객체는 데이터베이스와의 연결 및 DB 명령을 위한 모든 것을 가진 중요한 객체임 |
이후, DB 쿼리가 수행되면 SqlSessionFactory가 Connection(연결)을 생성하거나 원하는 SQL을 전달하고 결과값을 리턴하는 SqlSession 객체를 생성함 |
생성된 SqlSession을 참고해 mapper 인터페이스 호출하고 Mapper가 SqlSession을 호출해 Sql 실행 후 결과를 받음 |