mybatis는 sql명령어를 관리해주는 편리한 라이브러리이다.
sql명령어를 매번 문자열로 지정해서 하나하나 적어주는 방식보다 유지보수가 좋고, 효율성이 좋다. 그래서 mybatis를 통해 관리해줄 것이다.
// https://mvnrepository.com/artifact/org.mybatis/mybatis
implementation group: 'org.mybatis', name: 'mybatis', version: '3.5.7'
// https://mvnrepository.com/artifact/org.mybatis/mybatis-spring
implementation group: 'org.mybatis', name: 'mybatis-spring', version: '2.0.6'
// https://mvnrepository.com/artifact/org.springframework/spring-jdbc
implementation group: 'org.springframework', name: 'spring-jdbc', version: '5.3.22'
mybatis와 mybatis를 연동하는 스프링, 스프링과 jdbc를 연결하는 라이브러리이다.
이를 그림으로 표현하면 아래와 같다.
스프링 프레임워크에서 관리하는 일종의 설정 규칙을 만드는 것이다.
DataSource
sqlSessionFactory
sqlSession
sqlSessionFactory라는 공장에서 관리하는 생성자를 하나하나 정의하는 코드이다.
<property>
가 아닌 <constructor>
를 쓰면 공장에서 생성자를 만들어 사용하겠다는 의미이다.
@Configuration
@PropertySource("classpath:/application.properties")
@MapperScan(value = "hello.board.mapper")
// MyBatis와 HikariCP 연동을 위한 설정 클래스
public class DBConfig {
@Autowired
private ApplicationContext applicationContext;
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariConfig hikariConfig() {
return new HikariConfig();
}
// HikariCP를 이용해 DB 접속, 데이터풀을 가져옴
@Bean
public DataSource dataSource() throws Exception{
DataSource dataSource = new HikariDataSource(hikariConfig());
return dataSource;
}
// MyBatis 설정 관련 빈, 데이터풀에서 sql문을 관리하는 공장
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception{
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
// DB(Mysql)에서 읽어온 데이터를 담아올 도메인(DTO)의 패키지 경로를 설정 -> Mapper 파일에 편하게 클래스 명만 작성해서 사용
sqlSessionFactoryBean.setTypeAliasesPackage("hello.board.domain");
// 쿼리를 작성할 mapper 파일을 생성해 둘 경로(resources/mapper) -> 해당 경로에. xml로 끝나는 파일들을 스캔해서 설정
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:/mapper/*.xml"));
return sqlSessionFactoryBean.getObject();
}
// 장에서 관리하는 하나하나의 생성자를 정의, SqlSessionTemplate은 SqlSession을 구현
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
mapper는 매핑이라는 단어에서 유추할 수 있듯이 sql문(xml)을 메소드(java)로 매핑 시켜주는 것을 의미한다.
@Component
@MapperScan
public interface TestMapper {
Test test() throws Exception;
}
@mapper로 하나씩 매퍼를 등록할 수 있지만, @mapperScan으로 클래스패스를 지정해서 myBatis-sping 연동 모듈의 자동스캔기능을 사용할 수 있다.
@mapperScan의 사용은 다음과 같이 한다.
@Configuration
@MapperScan("org.mybatis.spring.sample.mapper")
public class AppConfig {
// ...
}
쿼리를 작성할 매퍼 xml을 2의 설정파일에 지정한 경로에 생성한다.
<?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="com.test.api.mapper.TestMapper">
<select id="test" parameterType="map" resultType="Test">
SELECT * FROM ${tblBoard}
</select>
</mapper>
Mapper Interface를 주입받아 사용할 서비스를 생성
@Service
public class TestService {
private final TestMapper testMapper;
@Autowired
public TestService(TestMapper testMapper) {
this.testMapper = testMapper;
}
public Test test() throws Exception {
return testMapper.test();
}
}
테스트 및 서비스를 사용하기 위해 컨트롤러를 생성
@RestController
public class TestController {
private final TestService testService;
@Autowired
public TestController(TestService testService) {
this.testService = testService;
}
@GetMapping(value = "/test")
public Test test() throws Exception {
return testService.test();
}
}
mybatis는 sql을 관리하는 만큼 sql의 관리 설정이나, sql문을 정의한 문서가 필요하여 만들어주었다.
// ---------추가----------
sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:/mybatis-config.xml"));
// ------ 추가 끝 ------------
이 문서에서 테이블이름이나, 컬럼의 이름을 변수화 시켜주는 설정을 한다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties>
<property name="tblBoard" value="test_board" />
<property name="colBno" value="bno" />
<property name="colTitle" value="title" />
<property name="colContent" value="content" />
<property name="colUserid" value="userid" />
</properties>
<typeAliases>
<package name="hello.board.domain" />
</typeAliases>
</configuration>
applicatioin.properties에서 DB주소에 스키마 이름이 빠져 있어서 생긴 오류이다.
# 변경 전
spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:3306/?autoReconnect=true&useSSL=false&&serverTimezone=UTC
# 변경 후
spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:3306/board?autoReconnect=true&useSSL=false&&serverTimezone=UTC
select 실행결과 받아야하는 값이 2개이상일때 TooManyResultsException 에러가 발생했다.
해결방법
1. 그래서 interface TestMapper, TestController코드, TestService의 코드들에서 test함수의 반환값을 Test
에서 List<Test>
로 바꿔주었다.
2. 또한 sql문을 작성하는 resource.mapper.TestMapper.xml
의 <select>
의 resultType을 Test에서 Map으로 바꿔주었다.
<!-- resource.mapper.TestMapper.xml -->
<select id="test" parameterType="map" resultType="Map">
SELECT * FROM ${tblBoard}
</select>
🌞 참고로 resource.mapper.TestMapper.xml
의 <select>
의 resultType만 바꿔주면 되는건가 싶어서 test메서드의 반환값을 Test로 바꿔보았지만 UnsatisfiedDependencyException 에러가 발생하였다. ㅅtest메서드의 반환값은List<Test>
으로 하는것이 맞는듯하다.
🤗 추가로 test메서드의 반환값은 List<Test>
로 해주고 select 문의 resultType을 Test로 바꿔주었더니 에러 없이 두개 이상의 값을 받아 올 수 있었다. 그 이유는 한 행(SELECT * FROM ${tblBoard}
)을 객체로 보기 때문에 한 행을 객체 Test로 차곡차곡 담은 뒤 mybatis가 알아서 리스트로 넣어주기 때문이다.
참고 사이트
https://www.devkuma.com/docs/mybatis/%EC%97%AC%EB%9F%AC-%EA%B0%9C%EC%9D%98-%EA%B2%B0%EA%B3%BC-%EC%96%BB%EA%B8%B0/
https://m.blog.naver.com/zxxne/222476370039
mapperScan
https://codingnojam.tistory.com/27
https://mybatis.org/spring/ko/mappers.html
DB 연결
https://veneas.tistory.com/entry/Spring-Boot-MyBatis-%EC%82%AC%EC%9A%A9%EB%B2%95-Mapper-MapperScan?category=881419
https://meaownworld.tistory.com/28
DB 커넥션 연결 설정
https://linked2ev.github.io/gitlog/2019/08/21/springboot-mvc-4-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-MyBatis-+-HikariCP-+-MariaDB-%EC%84%A4%EC%A0%95/
SqlSessionTemplate과 SqlSession
https://mybatis.org/spring/ko/sqlsession.html
hikariCP 연결 관련인듯??
https://frontierdev.tistory.com/215