국비지원 공부 정리/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 실행 후 결과를 받음