[JPA] ์ฝ”๋“œ๋กœ ๋ณด๋Š” OSIV ์™€ ๊ณ ์ฐฐ

2024. 1. 30. 14:51ยท๐Ÿ“‚ backend/spring

1. OSIV(Open Session In View) ๋ž€??

 

์ถœ์ฒ˜: ์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ

 

OSIV(Open Session In View)์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ ์˜์—ญ์„ ๋ทฐ(View)๊นŒ์ง€ ํ™•์žฅํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. Open Session In View๋ผ ๋ถˆ๋ฆฌ๋Š” ์ด์œ ๋Š” JPA์˜ ๊ตฌํ˜„์ฒด์ธ Hibernate ์—์„œ EntityManager์˜ ๊ตฌํ˜„์ฒด๋กœ Session ์„ ์‚ฌ์šฉํ•œ๋‹ค. JPA์—์„œ๋Š” OEIV(Open-EntityManager-In-View) ๋กœ ๋ถ€๋ฅด์ง€๋งŒ ํ†ต์ƒ์ ์œผ๋กœ Open-Session-In-View ๋กœ ๋ถ€๋ฅธ๋‹ค.

 

 

2. Spring-Boot ์˜ ํ”„๋กœํผํ‹ฐ ๊ธฐ๋ฐ˜ OSIV ์„ค์ • ๊ณผ์ •

Spring-Boot ๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์ž๋™ ์„ค์ •์„ ์ง€์›ํ•œ๋‹ค. JpaBaseconfiguration ์ถ”์ƒ ํด๋ž˜์Šค์˜ nested static class ์ธ JpaWebConfiguration ์—์— OSIV ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ์ธํ„ฐ์…‰ํ„ฐ์ธ OpenEntityanagerInViewInterceptor ๋ฅผ ํ™œ์„ฑ ์—ฌ๋ถ€๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค. spring.jpa.open-in-view ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌ๋˜๋ฉฐ ๋ณ„๋„์˜ ์„ค์ •์ด ์—†์„ ๊ฒฝ์šฐ์—๋Š” OpenEntityanagerInViewInterceptor ๋Š” ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜๊ณ  ์ธํ„ฐ์…‰ํ„ฐ๋กœ ๊ด€๋ฆฌ๋œ๋‹ค.

 

spring.jpa.open-in-view: false # default value = true
package org.springframework.boot.autoconfigure.orm.jpa;

// imports ...

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(JpaProperties.class)
public abstract class JpaBaseConfiguration implements BeanFactoryAware {

	private final DataSource dataSource;
    
	// ์—ฌ๊ธฐ์— JpaProperties
	private final JpaProperties properties; 

	private final JtaTransactionManager jtaTransactionManager;

	private ConfigurableListableBeanFactory beanFactory;

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnWebApplication(type = Type.SERVLET)
	@ConditionalOnClass(WebMvcConfigurer.class)
	@ConditionalOnMissingBean({ OpenEntityManagerInViewInterceptor.class, OpenEntityManagerInViewFilter.class })
	@ConditionalOnMissingFilterBean(OpenEntityManagerInViewFilter.class)
	@ConditionalOnProperty(prefix = "spring.jpa", name = "open-in-view", havingValue = "true", matchIfMissing = true)
	protected static class JpaWebConfiguration {

		private static final Log logger = LogFactory.getLog(JpaWebConfiguration.class);

		private final JpaProperties jpaProperties;

		protected JpaWebConfiguration(JpaProperties jpaProperties) {
			this.jpaProperties = jpaProperties;
		}

		// ์‹ค์ œ OSIV ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” OpenEntityManagerInViewInterceptor ๊ฐ€ ๋นˆ์œผ๋กœ ์„ ์–ธ๋˜๋Š” ๋ถ€๋ถ„
		@Bean
		public OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor() {
			if (this.jpaProperties.getOpenInView() == null) {
				logger.warn("spring.jpa.open-in-view is enabled by default. "
						+ "Therefore, database queries may be performed during view "
						+ "rendering. Explicitly configure spring.jpa.open-in-view to disable this warning");
			}
			return new OpenEntityManagerInViewInterceptor();
		}

		@Bean
		public WebMvcConfigurer openEntityManagerInViewInterceptorConfigurer(
				OpenEntityManagerInViewInterceptor interceptor) {
			return new WebMvcConfigurer() {

				@Override
				public void addInterceptors(InterceptorRegistry registry) {
					registry.addWebRequestInterceptor(interceptor);
				}

			};
		}

	}
}

 

 

 

3. OpenEntityManagerInViewInterceptor ์˜ ๊ธฐ๋ณธ ๋™์ž‘์„ ํ™•์ธํ•ด๋ณด์ž.

์‹ค์ œ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๊ฒฝ์šฐ์—๋Š” ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์š”์ฒญ์ด ์™„๋ฃŒ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋ฅผ ์ข…๋ฃŒํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด์™ธ์—๋„ ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๊ฐ€ ๊ด€๋ฆฌ๋˜๊ธฐ ์œ„ํ•œ TransactionSynchronizationManager, AsyncRequestInterceptor ์™€ ๊ฐ™์ด ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™”, ๋น„๋™๊ธฐ๋ฅผ ์œ„ํ•œ ์ž‘์—…์„ ์œ„ํ•œ ์„ค์ •์ด ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

package org.springframework.orm.jpa.support;

// imports ...

public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAccessor implements AsyncWebRequestInterceptor {

	public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";

	@Override
	public void preHandle(WebRequest request) throws DataAccessException {
		String key = getParticipateAttributeName();
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		if (asyncManager.hasConcurrentResult() && applyEntityManagerBindingInterceptor(asyncManager, key)) {
			return;
		}

		EntityManagerFactory emf = obtainEntityManagerFactory();
		if (TransactionSynchronizationManager.hasResource(emf)) {
			// ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™”์™€ ๊ด€๋ จ๋œ ๋กœ์ง
		} else {
			logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewInterceptor");

			// EntityManager ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
			try {
				EntityManager em = createEntityManager();
				EntityManagerHolder emHolder = new EntityManagerHolder(em);
				TransactionSynchronizationManager.bindResource(emf, emHolder);

				AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(emf, emHolder);
				asyncManager.registerCallableInterceptor(key, interceptor);
				asyncManager.registerDeferredResultInterceptor(key, interceptor);
			} catch (PersistenceException ex) {
				throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
			}
		}
	}

	@Override
	public void afterCompletion(WebRequest request, @Nullable Exception ex) throws DataAccessException {
		if (!decrementParticipateCount(request)) {
			EntityManagerHolder emHolder = (EntityManagerHolder)
				TransactionSynchronizationManager.unbindResource(obtainEntityManagerFactory());
			logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewInterceptor");
			EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager()); // 2. ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋ฅผ ๋‹ซ๋Š”๋‹ค.
		}
	}
}

 

 

4. ๋งŒ์•ฝ Filter ์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌ๋˜์–ด์•ผ ํ•œ๋‹ค๋ฉด?

Spring Security ์™€ ๊ฐ™์ด FilterChain ๊ธฐ๋ฐ˜์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ Open-Session-In-View ๋Š” ์•ˆํ‹ฐ ํŒจํ„ด์ด๋ผ ๋งํ•œ๋‹ค. ์š”์ฒญ์ด ์‹œ์ž‘, ์ข…๋ฃŒ๋˜๋Š” ์‹œ์ ๊นŒ์ง€ DB Connection ์„ ์žก๊ณ  ์žˆ์–ด ์‹ค์‹œ๊ฐ„ ์„œ๋น„์Šค์™€ ๊ฐ™์ด ํŠธ๋ž˜ํ”ฝ์— ๋ฏผ๊ฐํ•œ ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ์— ์„ฑ๋Šฅ ์ €ํ•˜ ์š”์†Œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ•˜์ง€๋งŒ ์‚ฌ๋‚ด์˜ ์‹œ์Šคํ…œ์ด ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ๋กœ ์ธํ•ด ํ•„ํ„ฐ ์ชฝ์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ๋˜์„œ ๋ถˆ๊ฐ€ํ”ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด OpenEntityManagerInViewFilter ์„ ์„ ์–ธํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. OpenEntityManagerInViewFilter ๋Š” ์Šคํ”„๋ง์—์„œ ์ง€์›ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๋นˆ์„ ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜์ž.

 

package org.springframework.orm.jpa.support;

// ์—ฌ๋Ÿฌ๊ฐ€์ง€ import

public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
// ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
}
// source : https://tecoble.techcourse.co.kr/post/2020-09-20-entity-lifecycle-2/

@Component
@Configuration
public class OpenEntityManagerConfig {
    @Bean
    public FilterRegistrationBean<OpenEntityManagerInViewFilter> openEntityManagerInViewFilter() {
        FilterRegistrationBean<OpenEntityManagerInViewFilter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
        filterFilterRegistrationBean.setFilter(new OpenEntityManagerInViewFilter());
        filterFilterRegistrationBean.setOrder(Integer.MIN_VALUE); // ์ตœ์šฐ์„  ์ˆœ์œ„๋กœ Filter ๋“ฑ๋ก
        return filterFilterRegistrationBean;
    }
}

 

 

5. ๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๋Š” open-session-in-view

ํ”ํžˆ open-session-in-view ๋ฅผ ์•ˆํ‹ฐ ํŒจํ„ด์ด๋ผ ๋ถ€๋ฅธ๋‹ค. ์ด์ „์— ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์‹ค์‹œ๊ฐ„ ํŠธ๋ž˜ํ”ฝ์ด ์ค‘์š”ํ•œ ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ, ์š”์ฒญ ์‹œ์ ์— EntityManager ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด์„œ DB Connection Pool ์˜ Connection ์„ ๋ถ™์žก๊ณ  ์žˆ์–ด Connection Pool ์ด ๊ณ ๊ฐˆ๋  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

open-session-in-view ๋ฅผ ํ™œ์„ฑํ™” ํ•  ๊ฒฝ์šฐ, DB ์ž‘์—…์ด ๋ชจ๋‘ ์™„๋ฃŒ๋˜๊ณ  ๋‹ค๋ฅธ ์™ธ๋ถ€ API ์š”์ฒญ์„ ๋Œ€๊ธฐํ•˜๋Š” ์‹œ๊ฐ„๊นŒ์ง€ Connection ์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด์™€ ๊ฐ™์€ ๋ณ‘๋ชฉ์ง€์ ์ด ์ƒ๊ธฐ๊ณ  ํ•ด๋‹น ๋กœ์ง์ด ๋งŽ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ConnectionPool ์˜ Connection ์„ ๋ชจ๋‘ ์žก๋Š”๋‹ค๋ฉด Connection ์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ๋‚˜์œ ์‚ฌ์šฉ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์—†๋‹ค๋ฉด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ ํ•ฉํ•œ ๊ฒƒ ๊ฐ™๋‹ค.

 

hikariCP ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๋“ค์˜ ๊ธฐ๋ณธ ๊ฐ’ ์ •๋„๋Š” ์ฐธ๊ณ ๋กœ ์•Œ๊ณ  ์žˆ์ž.

 

# ์ฃผ์˜ : DB ๋‹จ์œ„ - s, Spring Boot ๋‹จ์œ„ - ms
# Spring Boot ์„ค์ •์„ Database ์„ค์ •๋ณด๋‹ค ์ ๊ฒŒ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅ

spring.datasource.hikari.minimumIdle=30000 #30์ดˆ
spring.datasource.hikari.connectionTimeout=30000 #30์ดˆ
spring.datasource.hikari.maximumPoolSize=10
spring.datasource.hikari.idleTimeout=600000 # 10๋ถ„
spring.datasource.hikari.maxLifeTime=1800000 # 30๋ถ„
spring.datasource.hikari.autoCommit=true

 

๋น„๋ก thymeleaf, jsp ์™€ ๊ฐ™์€ ํ…œํ”Œ๋ฆฟ ์—”์ง„์„ ์–ด๋“œ๋ฏผ ํŽ˜์ด์ง€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ํŽธ์˜์„ฑ์„ ๊ฐ€์ ธ๋‹คw์ฃผ๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ ํŽธ๋ฆฌํ•จ์œผ๋กœ ์ธํ•ด ํ…œํ”Œ๋ฆฟ ์—”์ง„์— ์˜์กด์ ์ธ ์ฝ”๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  vue.js ๋‚˜ react ๋กœ ์ „ํ™˜ํ•  ๋•Œ์˜ ๊ณต์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ๊ธฐ์กด thymeleaf, jsp ์™€ ๊ฐ™์€ ํ…œํ”Œ๋ฆฟ ์—”์ง„๊ณผ open-session-in-view ํ™œ์„ฑํ™”ํ•ด์„œ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์ตœ๋Œ€ํ•œ ์—”ํ‹ฐํ‹ฐ ์ดˆ๊ธฐํ™”๋ฅผ ํ…œํ”Œ๋ฆฟ ์—”์ง„์—์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ํ•˜๊ณ , ์—”ํ‹ฐํ‹ฐ ๋Œ€์‹ ์— DTO ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ ์ž‘์—…์„ ํ•˜๋Š” ๊ฒƒ์ด ๋‚ฎ์€ ์˜์กด์„ฑ์„ ๊ธฐ๋ฐ˜ํ•ด์„œ ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์šฉ์ดํ•˜์ง€ ์•Š์„๊นŒ ์‹ถ๋‹ค.

 

  • ์‹ ๊ทœ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด open-session-in-view ๋น„ํ™œ์„ฑํ™” ํ•˜๊ธฐ
  • ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด open-session-in-view ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์ž‘์—…ํ•˜๊ธฐ (e.g. DTO)

 

6. summary

  1. OSIV ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ์š”์ฒญ, ์‘๋‹ต์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ํ™œ์„ฑํ™”ํ•˜๋Š” ์ „๋žต์„ ๋งํ•œ๋‹ค.
  2. OSIV ๋Š” OpenEntityManagerInViewInterceptor, OpenEntityManagerInViewFilter ๋ฅผ ํ†ตํ•ด ์˜์†ํ™” ๋ฒ”์œ„๊ฐ€ ํ™•์žฅ๋œ๋‹ค.
  3. OSIV ๋Š” ๋‹ค๋ฅธ ๋กœ์ง์˜ ์ฒ˜๋ฆฌ๊ฐ€ ๊ธธ์–ด์ง€๋Š”๋งŒํผ Connection ์„ ๋ถ™์žก๊ณ  ์žˆ์–ด ์ปค๋„ฅ์…˜ ๊ณ ๊ฐˆ์ด ๋  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋กœ ์ธํ•ด ์•ˆํ‹ฐ ํŒจํ„ด์ด๋‹ค. ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์—†๋‹ค๋ฉด ๋น„ํ™œ์„ฑํ™”ํ•ด์„œ ์‚ฌ์šฉํ•˜์ž. (๋น„ํ™œ์„ฑํ™” ํ• ๊ฒฝ์šฐ, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” @Transactional ๋‚ด๋ถ€์—์„œ๋งŒ ๊ด€๋ฆฌ๋œ๋‹ค.)

 

Reference

  • https://www.yes24.com/Product/Goods/19040233
  • https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.data.spring.datasource.hikari
  • https://tecoble.techcourse.co.kr/post/2020-09-20-entity-lifecycle-2/

'๐Ÿ“‚ backend > spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

hibernate.query.in_clause_parameter_padding = true ?  (1) 2024.03.06
JPA ์— UUID version 7 ์ ์šฉํ•˜๊ธฐ  (0) 2024.03.04
[Spring] Spring AOP ๋™์ž‘ ์•Œ์•„๋ณด๊ธฐ  (0) 2024.03.04
QueryDSL transform() ์—์„œ ๊ผญ @Transactional ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ   (0) 2024.01.29
ํ…Œ์ŠคํŠธ์—์„œ @Sql ๋กœ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ€์ง€ ์•Š์•˜๋˜ ์ด์œ  (with. custom TestExecutionListener)  (1) 2024.01.24
'๐Ÿ“‚ backend/spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • JPA ์— UUID version 7 ์ ์šฉํ•˜๊ธฐ
  • [Spring] Spring AOP ๋™์ž‘ ์•Œ์•„๋ณด๊ธฐ
  • QueryDSL transform() ์—์„œ ๊ผญ @Transactional ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 
  • ํ…Œ์ŠคํŠธ์—์„œ @Sql ๋กœ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ€์ง€ ์•Š์•˜๋˜ ์ด์œ  (with. custom TestExecutionListener)
cooper25
cooper25
  • cooper25
    dev cooper
    cooper25
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (84)
      • ๐Ÿ“‚ backend (34)
        • spring (19)
        • architecture (10)
        • test (5)
      • ๐Ÿ“‚ computer-science (5)
      • ๐Ÿ“‚ programming-language (12)
        • java (12)
      • ๐Ÿ“‚ infra (9)
        • mysql (4)
        • redis (2)
        • message-queue (3)
      • ๐Ÿ“‚ cloud (2)
        • aws (2)
      • ๐Ÿ“‚ frontend (1)
        • react (0)
      • ๐Ÿ“‚ education & lecture (16)
        • ์ธํ”„๋ผ ๊ณต๋ฐฉ (11)
        • ํ•ญํ”Œ ๋ฐฑ์—”๋“œ 7๊ธฐ (5)
      • ๐Ÿ“‚ ai (1)
        • claude (1)
      • ๐Ÿ“‚ etc (2)
        • ํšŒ๊ณ  (1)
        • ์ปจํผ๋Ÿฐ์Šค (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    ์Šคํ”„๋ง์บ ํ”„ ํ›„๊ธฐ
    spring
    AWS
    react
    spring AOP
    nGrinder
    gof
    kafka
    Redisson
    JPA
    mysql
    ๋™์‹œ์„ฑ
    ๊ฐ€์ƒ ๋ฉด์ ‘ ์‚ฌ๋ก€๋กœ ๋ฐฐ์šฐ๋Š” ๋Œ€๊ทœ๋ชจ ์„ค๊ณ„
    ํ•ญํ•ดํ”Œ๋Ÿฌ์Šค
    spring-batch
    ํšŒ๊ณ 
    ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค๊ณ„
    ์ธํ”„๋ผ๊ณต๋ฐฉ
    UUID
    spring camp 2025
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.6
cooper25
[JPA] ์ฝ”๋“œ๋กœ ๋ณด๋Š” OSIV ์™€ ๊ณ ์ฐฐ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”