JPA와 MyBatis가 오류없이 잘 작동하는지 테스트를 하기 위해 테스트 코드를 만들어 돌려보았다.
package com.springboot2.legacy;
import com.springboot2.legacy.dto.first.PokemonDto;
import com.springboot2.legacy.dto.second.ItemDto;
import com.springboot2.legacy.entity.first.PokemonEntity;
import com.springboot2.legacy.entity.second.ItemEntity;
import com.springboot2.legacy.mapper.first.PokemonMapper;
import com.springboot2.legacy.mapper.second.ItemMapper;
import com.springboot2.legacy.repository.first.PokemonRepository;
import com.springboot2.legacy.repository.second.ItemRepository;
import com.springboot2.legacy.service.first.PokemonService;
import com.springboot2.legacy.service.second.ItemService;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import java.util.List;
@SpringBootTest
public class DBConnectTest {
@Autowired
PokemonRepository pokemonRepository;
@Autowired
PokemonMapper pokemonMapper;
@Autowired
ItemRepository itemRepository;
@Autowired
ItemMapper itemMapper;
@Autowired
PokemonService pokemonService;
@Autowired
ItemService itemService;
@Test
void firstDB() {
List<PokemonEntity> all = pokemonRepository.findAll();
all.forEach(ent -> System.out.println("FIRST DB JPA : " + ent.getPokemonId() + " : " + ent.getName()));
List<PokemonDto> pokemons = pokemonMapper.getPokemons();
pokemons.forEach(dto -> System.out.println("FIRST DB MyBatis : " + dto.getPokemonId() + " : " + dto.getName()));
}
@Test
void secondDB() {
List<ItemEntity> all = itemRepository.findAll();
all.forEach(ent -> System.out.println("SECOND DB JPA : " + ent.getPrice() + ", " + ent.getStockQuantity()));
List<ItemDto> items = itemMapper.getItems();
items.forEach(dto -> System.out.println("SECOND DB MyBatis : " + dto.getPrice() + ", " + dto.getStockQuantity()));
}
}
결과를 확인해 보았더니
FIRST DB JPA : 121 : Pikachu
FIRST DB JPA : 122 : Bulbasaur
FIRST DB JPA : 123 : Charmander
FIRST DB JPA : 124 : Squirtle
FIRST DB JPA : 125 : Butterfree
FIRST DB JPA : 126 : Rattata
FIRST DB JPA : 127 : Clefairy
FIRST DB JPA : 128 : Arbok
FIRST DB JPA : 129 : Diglett
FIRST DB JPA : 130 : Kadabra
FIRST DB MyBatis : null : Pikachu
FIRST DB MyBatis : null : Bulbasaur
FIRST DB MyBatis : null : Charmander
FIRST DB MyBatis : null : Squirtle
FIRST DB MyBatis : null : Butterfree
FIRST DB MyBatis : null : Rattata
FIRST DB MyBatis : null : Clefairy
FIRST DB MyBatis : null : Arbok
FIRST DB MyBatis : null : Diglett
FIRST DB MyBatis : null : Kadabra
SECOND DB JPA : 10000, 99
SECOND DB JPA : 20000, 98
SECOND DB JPA : 20000, 197
SECOND DB JPA : 40000, 296
SECOND DB MyBatis : 10000, 0
SECOND DB MyBatis : 20000, 0
SECOND DB MyBatis : 20000, 0
SECOND DB MyBatis : 40000, 0
이런 결과가 나왔다.
JPA 사용 시에는 값을 제대로 가져오고 있는 반면에 MyBatis 사용 시에는 몇몇 값을 가져오지 못하는 현상이 발견되었다.
@Data
public class PokemonDto {
private Long pokemonId; // CamelCase
private String name;
private String type;
}
확인해보니 두 단어 이상으로 이루어져 CamelCase를 사용하는 필드값만 불러오지 못하고 있었다.
분명 application.yml에 MyBatis 설정에 SnakeCase를 CamelCase로 변경해주는 설정을 true로 해놓았는데 적용되고 있지 않은 듯하다.
알고보니 DB를 하나만 사용할 경우, application.yml 설정을 바로 사용하지만 다중 DB를 사용할 경우에는 추가로 설정해주어야했다.
이를 위해 MyBatis 공통 부분에 추가 셋팅을 하였다.
package com.springboot2.legacy.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Map;
@Configuration
public class DBConfig {
@Autowired
private HibernateProperties hibernateProperties;
@Autowired
private JpaProperties jpaProperties;
// MyBatis 프로퍼티 객체 추가
@Autowired
private MybatisProperties mybatisProperties;
protected void setConfigEntityManagerFactory(LocalContainerEntityManagerFactoryBean factory) {
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
Map<String, Object> properties = hibernateProperties.determineHibernateProperties(
jpaProperties.getProperties(), new HibernateSettings()
);
factory.setJpaVendorAdapter(vendorAdapter);
factory.setJpaPropertyMap(properties);
factory.afterPropertiesSet();
}
protected void setConfigSqlSessionFactory(SqlSessionFactoryBean sessionFactoryBean, DataSource dataSource) throws Exception {
sessionFactoryBean.setDataSource(dataSource);
// sessionFactoryBean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:/mybatis/config/mybatis-config.xml"));
sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mybatis/mapper/*.xml"));
// yml로 사용하도록 추가
sessionFactoryBean.setTypeAliasesPackage(mybatisProperties.getTypeAliasesPackage());
// Configuration에 MyBatis 프로퍼티를 셋팅
org.apache.ibatis.session.Configuration configuration = sessionFactoryBean.getObject().getConfiguration();
// SnakeCase -> CamelCase 설정
configuration.setMapUnderscoreToCamelCase(mybatisProperties.getConfiguration().isMapUnderscoreToCamelCase());
sessionFactoryBean.setConfiguration(configuration);
}
}
# Mybatis 설정
mybatis:
configuration:
map-underscore-to-camel-case: true
call-setters-on-nulls: true
mapper-locations: classpath:/mybatis/mapper/*.xml
# config-location: classpath:/mybatis/config/mybatis-config.xml
type-aliases-package: "com.springboot2.legacy.dto" # 추가
추가를 하면서 MyBatis 설정을 전부 yml로 컨트롤하도록 변경했다.
FIRST DB JPA : 121 : Pikachu
FIRST DB JPA : 122 : Bulbasaur
FIRST DB JPA : 123 : Charmander
FIRST DB JPA : 124 : Squirtle
FIRST DB JPA : 125 : Butterfree
FIRST DB JPA : 126 : Rattata
FIRST DB JPA : 127 : Clefairy
FIRST DB JPA : 128 : Arbok
FIRST DB JPA : 129 : Diglett
FIRST DB JPA : 130 : Kadabra
FIRST DB MyBatis : 121 : Pikachu
FIRST DB MyBatis : 122 : Bulbasaur
FIRST DB MyBatis : 123 : Charmander
FIRST DB MyBatis : 124 : Squirtle
FIRST DB MyBatis : 125 : Butterfree
FIRST DB MyBatis : 126 : Rattata
FIRST DB MyBatis : 127 : Clefairy
FIRST DB MyBatis : 128 : Arbok
FIRST DB MyBatis : 129 : Diglett
FIRST DB MyBatis : 130 : Kadabra
SECOND DB JPA : 10000, 99
SECOND DB JPA : 20000, 98
SECOND DB JPA : 20000, 197
SECOND DB JPA : 40000, 296
SECOND DB MyBatis : 10000, 99
SECOND DB MyBatis : 20000, 98
SECOND DB MyBatis : 20000, 197
SECOND DB MyBatis : 40000, 296
이후 테스트 결과, 값을 전부 잘 가져오는 것을 확인했다.
그러나 이 설정에는 한가지 단점이 있는데, 만약 MyBatis에서 사용하는 프로퍼티가 늘어나는 경우에 DBConfig와 application.yml 두 군데를 수정해야한다는 것이다. 해당 문제를 풀어보려했지만 방법을 찾지 못하여, 결국 MyBatis의 설정은 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>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
<typeAliases>
<package name="com.springboot2.legacy.dto"/>
</typeAliases>
</configuration>
이 문제는 MyBatis 3이 나오면서 해결할 수 있었다. 다음 편에 해결 방법에 대해 적어보겠다.
'좌충우돌 개발기! > DB 설정' 카테고리의 다른 글
[Spring Boot] (6)스프링부트 2.x / 3.x 에서 DB 사용 예제 (0) | 2023.08.24 |
---|---|
[Spring Boot] (5)다중 DB 환경에서 QueryDSL 사용하기 (0) | 2023.08.24 |
[Spring Boot] (4) 스프링부트 3에서의 QueryDSL 설정 변경 (0) | 2023.08.23 |
[Spring Boot] (3) MyBatis 3에서의 DB 설정 (0) | 2023.08.22 |
[Spring Boot] (1) DB 사용을 위한 셋팅 구성 (0) | 2023.08.20 |