๐Ÿ“Œ Spring Boot ํŠธ๋žœ์žญ์…˜ ๋ถ„๋ฆฌ ์„ค์ • (MyBatis + JPA)

My Pale Blue Dotยท2025๋…„ 5์›” 8์ผ

SPRING BOOT

๋ชฉ๋ก ๋ณด๊ธฐ
9/40
post-thumbnail

๐Ÿ“… ๋‚ ์งœ

2025-05-08

๐Ÿ“ ํ•™์Šต ๋‚ด์šฉ

1๏ธโƒฃ ํŠธ๋žœ์žญ์…˜ ๋ถ„๋ฆฌ์˜ ํ•„์š”์„ฑ

  • MyBatis์™€ JPA๋Š” ๋‚ด๋ถ€ ํŠธ๋žœ์žญ์…˜ ๋งค์ปค๋‹ˆ์ฆ˜์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๊ฐ€ ์ถฉ๋Œํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Spring์—์„œ๋Š” @Transactional์—์„œ ์‚ฌ์šฉํ•  ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•จ์œผ๋กœ์จ ํ˜ผ์„ ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

2๏ธโƒฃ ์„ค์ • ํŒŒ์ผ ์ •๋ฆฌ

โœ… TxConfig.java

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages ="com.example.demo.domain.repository",
        transactionManagerRef = "jpaTransactionManager"
)
public class TxConfig {

    @Autowired
    private DataSource dataSource;

    // MyBatis ๋˜๋Š” ๊ธฐ๋ณธ JDBC์šฉ ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €
    @Bean(name = "dataSourceTransactionManager")
    public DataSourceTransactionManager transactionManager2() {
        return new DataSourceTransactionManager(dataSource);
    }

    // JPA์šฉ ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €
    @Bean(name = "jpaTransactionManager")
    public JpaTransactionManager jpaTransactionManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

โœ… JpaConfig.java

@Configuration
@EntityScan(basePackages = {"com.example.demo.domain.entity"})
@EnableJpaRepositories(
        basePackages = {"com.example.demo.domain.repository"},
        transactionManagerRef = "jpaTransactionManager"
)
public class JpaConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        factoryBean.setPackagesToScan("com.example.demo.domain.entity");

        Map<String, Object> properties = new HashMap<>();
        properties.put("hibernate.hbm2ddl.auto", "update");
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        properties.put("hibernate.show_sql", true);
        properties.put("hibernate.format_sql", true);
        factoryBean.setJpaPropertyMap(properties);

        return factoryBean;
    }

    // โš ๏ธ ์‹ค๋ฌด์—์„œ๋Š” dev ํ™˜๊ฒฝ์—์„œ๋งŒ ๋™์ž‘ํ•˜๋„๋ก @Profile("dev") ์ถ”๊ฐ€ ๊ถŒ์žฅ
    @Bean
    public DataSourceInitializer dataSourceInitializer() {
        DataSourceInitializer initializer = new DataSourceInitializer();
        initializer.setDataSource(dataSource);
        initializer.setDatabasePopulator(databasePopulator());
        return initializer;
    }

    private DatabasePopulator databasePopulator() {
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScript(new ClassPathResource("schema.sql"));
        populator.addScript(new ClassPathResource("data.sql"));
        return populator;
    }
}

3๏ธโƒฃ ํŠธ๋žœ์žญ์…˜ ์„œ๋น„์Šค ์˜ˆ์ œ

โœ… TxTestService.java

@Service
@Slf4j
public class TxTestService {

    @Autowired
    private MemoMapper memoMapper;

    @Transactional(rollbackFor = SQLException.class, transactionManager = "dataSourceTransactionManager")
    public void addMemoTx(MemoDto dto) throws Exception {
        log.info("MyBatis Insert ์‹คํ–‰");
        memoMapper.insert(dto);
        throw new SQLException(); // ๋กค๋ฐฑ ํ…Œ์ŠคํŠธ์šฉ ์˜ˆ์™ธ
    }

    @Autowired
    private MemoRepository memoRepository;

    @Transactional(rollbackFor = SQLException.class, transactionManager = "jpaTransactionManager")
    public void addMemoTx2(MemoDto dto) throws Exception {
        log.info("JPA Insert ์‹คํ–‰");
        Memo memo = new Memo();
        memo.setId(dto.getId());
        memo.setText(dto.getText());
        memoRepository.save(memo);
        throw new SQLException(); // ๋กค๋ฐฑ ํ…Œ์ŠคํŠธ์šฉ ์˜ˆ์™ธ
    }
}

4๏ธโƒฃ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

โœ… TxTestServiceTest.java

@SpringBootTest
class TxTestServiceTest {

    @Autowired
    private TxTestService txTestService;

    @Test
    void t2() throws Exception {
        txTestService.addMemoTx(new MemoDto(1, "TEST1")); // MyBatis ํŠธ๋žœ์žญ์…˜ ํ…Œ์ŠคํŠธ
    }

    @Test
    void t3() throws Exception {
        txTestService.addMemoTx2(new MemoDto(1, "TEST1")); // JPA ํŠธ๋žœ์žญ์…˜ ํ…Œ์ŠคํŠธ
    }
}

๐Ÿ”ฅ ์ •๋ฆฌ

  • MyBatis์™€ JPA ๊ฐ๊ฐ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ถฉ๋Œ ์—†์ด ๋ณ‘ํ–‰ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • @Transactional(transactionManager = "...")๋กœ ๋ช…์‹œ ์ง€์ • ํ•„์ˆ˜
  • ์ดˆ๊ธฐํ™” ์Šคํฌ๋ฆฝํŠธ๋Š” @Profile("dev") ๋“ฑ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์‹ค๋ฌด์— ์ ํ•ฉ
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋กœ ๋กค๋ฐฑ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋ฉฐ ์•ˆ์ •์„ฑ ํ™•๋ณด ๊ฐ€๋Šฅ

๐Ÿ”— ์ฐธ๊ณ  ์ž๋ฃŒ


๋А๋‚€ ์ 

์ด๋ฒˆ ์‹ค์Šต์„ ํ†ตํ•ด ํ•˜๋‚˜์˜ ํ”„๋กœ์ ํŠธ์—์„œ MyBatis์™€ JPA๋ฅผ ๋™์‹œ์— ์‚ฌ์šฉํ•  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ํŠธ๋žœ์žญ์…˜ ์ถฉ๋Œ ๋ฌธ์ œ๋ฅผ ์‚ฌ์ „์— ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๋ฅผ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋กœ ๊ฒ€์ฆํ•˜๋Š” ๊ณผ์ •์€ ์‹ค๋ฌด์—์„œ๋„ ๋งค์šฐ ์œ ์šฉํ•  ๊ฒƒ์ด๋‹ค.


profile
Here, My Pale Blue.๐ŸŒ

0๊ฐœ์˜ ๋Œ“๊ธ€