Spring

SpringBoot + JPA 멀티 연동하기

쿠카이든 2023. 1. 12. 09:54
728x90
SpringBoot + JPA 다중 연동

 

1. 다중 DB 설정 시, 알아야 할 것

  1. 다중 DB설정은 Auto Configuration 되지 않기 때문에 설정파일(application.yml or application.properties) 값을 읽어와서 연동 할 DB 수 만큼 Datasource를 수동 설정해야함
  • 주요 설정 내용
    • 리소스 경로 설정
      • Repository basePackages 경로 설정
      • Entity 경로 설정
    • DB 정보 설정(Datasource)
      • driver 이름
      • URL
      • Id/Password
    • Hibernate 설정
      • ddl-auto
      • dialect
  1. 설정된 다중 DB는 Repository package 명으로 구분
  2. 초기 설정이 복잡한 편이나, 천천히 살펴보면 크게 어렵지 않음

2. 소스코드

이 글에서는 1개의 Entity로 2개의 Database에 값을 넣는 예제로 진행합니다.

2-1. Entity

  • 두 개의 DB에서 공용으로 사용할 Entity를 생성합니다.
package com.jpa.master.entity;

@Entity
@Table(schema = "users")
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	private String name;

	@Column(unique = true, nullable = false)
	private String email;

	private int age;
}

2-2. Repository

  • 서로 다른 패키지에 User Repository를 작성 (패키지가 다르다고 하여 파일명을 동일하게 하면 안됨)
package com.jpa.master.repository;

@Repository
public interface UserMasterRepository extends JpaRepository<User, Integer> {}
package com.jpa.second.repository;

@Repository
public interface UserSecondRepository extends JpaRepository<User, Integer> {}

2-3. DB Configuration

2-3-1 application.properties

#### Master DataSource Configuration1
spring.datasource.username=[user]
spring.datasource.password=[Password]
spring.datasource.jdbcUrl=[URL]
#### Second DataSource Configuration2
spring.second-datasource.username=[user]
spring.second-datasource.password=[Password]
spring.second-datasource.jdbcUrl=[URL]

2-3-2 Main Datasource 설정

  • Master DB용 java 설정파일 생성
  • 설정 파일은 다음과 같이 구성되어 있음
    • DataSource 설정
    • EntityManagerFactory 설정
    • TransactionManager 설정

다중 DB를 설정할 때는, @Primary 어노테이션을 이용하여 Master가되는 Datasouce를 지정해야합니다.

@Configuration
@PropertySource({ "classpath:application.properties" })
@EnableJpaRepositories(
    basePackages = "com.jpa.master.repository", // Master Repository 경로
    entityManagerFactoryRef = "masterEntityManager", 
    transactionManagerRef = "masterTransactionManager"
)
public class MainDatabaseConfig {
	@Autowired
	private Environment env;

	@Bean
	@Primary
	public LocalContainerEntityManagerFactoryBean masterEntityManager() {
		LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
		em.setDataSource(masterDataSource());
        
		//Entity 패키지 경로
        em.setPackagesToScan(new String[] { "com.jpa.master.entity" });
	
		HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
		em.setJpaVendorAdapter(vendorAdapter);
        
        //Hibernate 설정
		HashMap<String, Object> properties = new HashMap<>();
		properties.put("hibernate.hbm2ddl.auto",env.getProperty("hibernate.hbm2ddl.auto"));
		properties.put("hibernate.dialect",env.getProperty("hibernate.dialect"));
		em.setJpaPropertyMap(properties);
		return em;
	}
	
	@Primary
	@Bean
	@ConfigurationProperties(prefix="spring.datasource")
	public DataSource masterDataSource() {
		return DataSourceBuilder.create().build();
	}
	
	@Primary
	@Bean
	public PlatformTransactionManager masterTransactionManager() {	
		JpaTransactionManager transactionManager = new JpaTransactionManager();
		transactionManager.setEntityManagerFactory(masterEntityManager().getObject());
		return transactionManager;
	}
}

2-3-3 Second Datasource 설정

  • 두번째 DB용 java 설정파일 생성 (설정 파일 구성은 메인과 동일함)
  • 소스코드 복붙하다가 하는 실수
  • @Primary 어노테이션은 꼭 지워야 함
@Configuration
@PropertySource({ "classpath:application.properties" })
@EnableJpaRepositories(
    basePackages = "com.jpa.second.repository", // Second Repository 경로
    entityManagerFactoryRef = "secondEntityManager", 
    transactionManagerRef = "secondTransactionManager"
)
public class SecondConfig {
	@Autowired
	private Environment env;

	@Bean
	public LocalContainerEntityManagerFactoryBean secondEntityManager() {
		LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
		em.setDataSource(secondDataSource());
		em.setPackagesToScan(new String[] { "com.jpa.master.entity" });

		HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
		em.setJpaVendorAdapter(vendorAdapter);
		HashMap<String, Object> properties = new HashMap<>();
		properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
		properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
		em.setJpaPropertyMap(properties);
		return em;
	}

	@Bean
	@ConfigurationProperties(prefix="spring.second-datasource")
	public DataSource secondDataSource() {
		return DataSourceBuilder.create().build();
	}

	@Bean
	public PlatformTransactionManager secondTransactionManager() {
		JpaTransactionManager transactionManager = new JpaTransactionManager();
		transactionManager.setEntityManagerFactory(secondEntityManager().getObject());
		return transactionManager;
	}
}

4. Test

  • 간단한 Insert Test 코드 작성
@RunWith(SpringJUnit4ClassRunner.class)
@AutoConfigureTestDatabase(replace = Replace.NONE)
@SpringBootTest
public class JPAMultipleDBTest {
	@Autowired
	UserMasterRepository masterRepo;
	
	@Autowired
	UserSecondRepository secondRepo;

	@Test
	public void insertTest() {
		User user = new User();
		user.setAge(28);
		user.setEmail("test@spring.com");
		user.setName("name");
		
		secondRepo.save(user);
		masterRepo.save(user);
	}
}

4.1 hibernate 로그 확인

4.2 DB 데이터 확인

  • 테이블이 각 DB에 생성되었음
  • DB 데이터 확인
728x90