SpringBoot 프로젝트와 MySQL Database를 연결하는 방법을 정리하고자 한다.
제목에 LAB이 붙은 포스팅은 앞으로 개발하면서 마주쳤던 에러를 기록하고 어떻게 해결했는지를 정리하는 포스팅으로 작성하고자 한다!
우선 필자는 운동 루틴을 기록하는 기능을 구현하고자 한다.
우선 시작하기에 앞서 어떤 기능으로 미니 프로젝트를 진행해볼까 조금 고민했다.
필자는 간단하게 사용자가 수행할 수 있는 운동을 설정하고 운동을 선택하여 데일리 루틴을 관리할 수 있는 CRUD 프로젝트를 만들어볼까 한다.
우선 테이블 설계는 다음과 같다.
테이블은 크게 4가지로 구성된다.
테이블 구성
- user_profile : 사용자의 신체 정보
- exercise : 운동 종류 정보
- routine : 운동 세부 계획 정보
- workout_log : 실제 운동 수행 기록
이후에 더 추가되거나 수정될 수 있지만 지금은 이정도로만 정리하고 개발해보자
우선 필자는 수업에서 사용한 것과 동일한 방식인 Hikari를 사용해서 MySQL DB와 연결하려고 한다.
따라서 DataBaseConfiguration.java를 생성하고 DB 설정 정보를 빈으로 등록하고 관리할 예정이다.
우선 resources/application.properties
에서 설정 정보를 추가해보자
resources/application.properties
spring.application.name=MyProject spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:3306/health?useUnicode=true&characterEncoding=utf-8&serverTimeZone=Asia/Seoul spring.datasource.hikari.username=root spring.datasource.hikari.password= // workbench 비밀번호 spring.datasource.hikari.connection-test-query=select 1
설정 정보는 사실 간단하다.
어떤 DB Driver를 사용할건지, url주소는 어디인지, DB에 접근하기 위해 필요한 아이디와 비밀번호를 추가해서 관리하면 된다.
이제 이 설정 정보를 가져와서 빈으로 등록해야 SpringBoot가 실행될 때 자동으로 DB와 연결된다!
빈으로 등록하기 위해 별도의 클래스를 생성해서 관리하자
여기서 필자는 Hikari를 사용하여 데이터베이스 커넥션 풀을 관리할 예정이다.
우선 디렉토리 구조와 코드는 다음과 같다.
디렉토리 구조
Sample Code - DataBaseConfiguration.java
@Configuration @PropertySource("classpath:/application.properties") public class DataBaseConfiguration { @Bean @ConfigurationProperties(prefix = "spring.datasource.hikari") public HikariConfig hikariConfig() { return new HikariConfig(); } @Bean public DataSource dataSource() { return new HikariDataSource(hikariConfig()); } }
Spring의 데이터베이스 설정은 여러 단계를 거쳐 이루어진다.
우선 @PropertySource("classpath:/application.properties")
를 통해 설정 파일의 위치를 지정한다.
여기서 classpath는 프로젝트의 리소스 디렉토리를 의미하며, 이를 통해 스프링은 application.properties 파일을 찾아 설정값들을 로드할 수 있다.
이렇게 로드된 설정값들은 @ConfigurationProperties(prefix = "spring.datasource.hikari")
어노테이션을 통해 접근할 수 있다.
hikariConfig() 메서드에서 이 어노테이션을 사용하면, application.properties에 저장된 "spring.datasource.hikari" 로 시작하는 모든 설정값들이 자동으로 HikariConfig 객체에 매핑된다.
마지막으로 dataSource() 메서드에서는 이렇게 설정된 HikariConfig를 바탕으로 실제 데이터베이스 연결을 관리할 HikariDataSource를 생성한다.
DataSource는 데이터베이스 연결을 관리하는 인터페이스로, 이를 통해 스프링은 효율적으로 데이터베이스 커넥션을 관리할 수 있다!
Result View
DB와 잘 연결되는 모습을 볼 수 있다 👀
데이터베이스 연결 설정에 이어서, MyBatis를 통한 SQL 매핑과 실행을 위한 설정을 추가해야 한다.
MyBatis는 자바 객체와 SQL문 사이의 자동 매핑을 지원하는 프레임워크로, 보다 편리한 데이터베이스 작업을 가능하게 해준다.
SqlSessionFactory는 MyBatis의 핵심 컴포넌트로, 데이터베이스 연결과 SQL 실행을 관리한다.
다음은 SqlSessionFactory를 설정하는 코드이다.
Sample Code
@Bean SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean(); // 데이터베이스 연결 설정 sessionFactoryBean.setDataSource(dataSource); // SQL 매퍼 파일 위치 설정 sessionFactoryBean.setMapperLocations( applicationContext.getResources("classpath:/mapper/**/sql-*.xml") ); // MyBatis 설정 org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(true); sessionFactoryBean.setConfiguration(configuration); return sessionFactoryBean.getObject(); }
이 설정의 각 부분을 자세히 살펴보자.
우선, 이전에 생성한 DataSource를 매개변수로 넘겨서 연결 설정을 수행한다.
다음으로 SQL 매퍼 파일의 위치를 지정한다.
여기서 "classpath:/mapper/**/sql-*.xml"
패턴은 mapper 디렉토리 아래에 있는 모든 sql- 접두어를 가진 XML 파일을 매퍼로 인식하겠다는 의미이다.
그리고 setMapUnderscoreToCamelCase(true)를 통해 데이터베이스의 칼럼명과 자바 객체의 필드명을 자동으로 매핑해준다.
예를 들어 데이터베이스의 user_name이라는 칼럼은 자바 객체의 userName 필드로 자동 변환된다.
(외부에 설정하니 원하는대로 동작하지 않아서 sqlSessionFactory 메서드 내부로 넣었다 😅)
즉, 간단하게 SqlSessionFactory에서 필요한 설정 정보는 데이터 소스 연결
& SQL 매퍼 설정
이 두 가지이다.
SqlSessionFactory 설정에 이어서 SqlSessionTemplate을 설정한다.
우선 코드부터 살펴보자
Sample Code
@Bean SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); }
이전에 구현한 SqlSessionFactory를 SqlSessionTemplate의 매개변수로 넘기면서 빈으로 등록한다.
SqlSessionTemplate은 MyBatis의 SqlSession 인터페이스를 구현한 클래스로, 실제 데이터베이스 작업을 수행할 때 사용된다.
그런데 이렇게 실행하면 다음과 같이 오류가 발생한다.
Result View
로그를 살펴보면 SqlSessionFactory를 생성하는 곳에서 NullPointException이 발생한다.
이는 "classpath:/mapper/**/sql-*.xml"
에 매핑되는 파일이 없어서 발생하는 오류이다.
따라서, 해당 경로에 매핑되는 파일을 하나 만들어두자!
MyBatis에서 매퍼는 자바 인터페이스와 SQL문을 연결해주는 중요한 역할을 한다.
매퍼를 통해 자바 코드에서 데이터베이스 작업을 더욱 객체지향적으로 수행할 수 있다.
정리해보면 매퍼 설정은 크게 두 부분으로 나뉜다.
XML 파일에서 SQL문을 정의하고, 자바 인터페이스에서 이를 호출하는 메서드를 선언한다.
Sample Code
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="demo.mapper.UserMapper"></mapper>
UserMapper
@Mapper public interface UserMapper { }
디렉토리 구조
디렉토리 구조 사진에서 빨간색으로 색칠된 부분을 추가해주면 된다.
resources/mapper 하위에 정의된 XML 파일에서 가장 중요한 부분을 꼽으라면 namespace 속성을 선택할 것이다.
namespace는 매퍼 XML과 자바 인터페이스를 연결해주는 다리 역할을 한다.
따라서, namespace에 지정된 경로는 실제 자바 인터페이스의 전체 경로와 일치해야 한다!
(namespace에서 정의한 경로와 디렉토리 구조를 살펴보자)
다음으로 UserMapper에서 사용된 @Mapper
어노테이션은 이 인터페이스가 MyBatis의 매퍼임을 스프링에게 알려준다.
스프링은 이 인터페이스를 구현한 프록시 객체를 자동으로 생성하여 빈으로 등록하고 호출할 때마다 이를 통해 SQL문을 호출한다.
DB 연결 세팅을 혼자 할 수 있는가?
라고 묻는다면 아직은 참고 자료가 없으면 어려울 것 같다.
하지만, 미니 프로젝트를 진행하면서 사용된 코드를 이해하는 것을 목표로 해보자 👊