@Transactional 애너테이션을 적용해도 매번 session을 맺어서 처리하는 이유
3919
投稿した質問数 1
@Transactional(rollbackFor = Exception.class)
public int testTran(DatasetList dsList) {
Dataset dsParam = DatasetUtil.getGdsParam(dsList);
// Dataset을 SQL에 적용할 변수형인 Map으로 변환하면서 사용자 정보 입력
Map mapParam = DatasetUtil.getMap(dsParam, DatasetUtil.UPPER_CASE);
int iRes1 = codemap.updateTran1(mapParam);
log.info("==================== ||||||22222222222222||||||| ====================");
int iRes2 = codemap.updateTran2(mapParam); //미존재테이블로 에러 발생
log.info("==================== |||||||3333333333333|||||| ====================");
return iRes2;
}[2023-06-28 16:07:47:67472] [http-nio-8808-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - POST "/web/common/CodeAction?mode=testTran", parameters={masked}
[2023-06-28 16:07:47:67473] [http-nio-8808-exec-3] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to com.skcc.nxcus_spring.usrcode.action.codecontroller#testTran(HttpServletRequest, HttpServletResponse)
[2023-06-28 16:07:47:67473] [http-nio-8808-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
[2023-06-28 16:07:47:67473] [http-nio-8808-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@628385f5] was not registered for synchronization because synchronization is not active
[2023-06-28 16:07:47:67473] [http-nio-8808-exec-3] DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
[2023-06-28 16:07:47:67474] [http-nio-8808-exec-3] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [HikariProxyConnection@1752952453 wrapping net.sf.log4jdbc.sql.jdbcapi.ConnectionSpy@4499b10a] will not be managed by Spring
[2023-06-28 16:07:47:67474] [http-nio-8808-exec-3] DEBUG c.s.n.m.nxmdb.CodeMapper.updateTran1 - ==> Preparing: UPDATE COM_COMMON_COD SET COMM_NM = 'Transactional111' WHERE COMM_GRP_CD = 'MEMSTS' AND COMM_CD = 'A'
[2023-06-28 16:07:47:67474] [http-nio-8808-exec-3] DEBUG c.s.n.m.nxmdb.CodeMapper.updateTran1 - ==> Parameters:
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] DEBUG jdbc.sqltiming - com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
1. UPDATE
COM_COMMON_COD
SET
COMM_NM = 'Transactional111'
WHERE
COMM_GRP_CD = 'MEMSTS'
AND COMM_CD = 'A'
{executed in 3 msec}
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] DEBUG c.s.n.m.nxmdb.CodeMapper.updateTran1 - <== Updates: 1
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@628385f5]
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] INFO c.s.n.usrcode.biz.codeservice - ==================== ||||||22222222222222||||||| ====================
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@532be999] was not registered for synchronization because synchronization is not active
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [HikariProxyConnection@471746278 wrapping net.sf.log4jdbc.sql.jdbcapi.ConnectionSpy@4499b10a] will not be managed by Spring
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] DEBUG c.s.n.m.nxmdb.CodeMapper.updateTran2 - ==> Preparing: UPDATE COM_COMMON_COD SET COMM_NM = 'Transactional2222' WHERE COMM_GRP_CD = 'MEMSTS' AND COMM_CD = 'D'
[2023-06-28 16:07:47:67477] [http-nio-8808-exec-3] DEBUG c.s.n.m.nxmdb.CodeMapper.updateTran2 - ==> Parameters:
[2023-06-28 16:07:47:67478] [http-nio-8808-exec-3] DEBUG jdbc.sqltiming - com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
1. UPDATE
COM_COMMON_COD
SET
COMM_NM = 'Transactional2222'
WHERE
COMM_GRP_CD = 'MEMSTS'
AND COMM_CD = 'D'
{executed in 1 msec}
[2023-06-28 16:07:47:67478] [http-nio-8808-exec-3] DEBUG c.s.n.m.nxmdb.CodeMapper.updateTran2 - <== Updates: 1
[2023-06-28 16:07:47:67478] [http-nio-8808-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@532be999]
[2023-06-28 16:07:47:67478] [http-nio-8808-exec-3] INFO c.s.n.usrcode.biz.codeservice - ==================== |||||||3333333333333|||||| ====================
[2023-06-28 16:07:47:67478] [http-nio-8808-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - Completed 200 OK
@Transactional 애너테이션을 적용해도 각각의 sql 마다 매번 session을 맺어서 처리하는데요. 이유를 잘 모르겠습니다. 설정문제일까요?
回答 2
2
원인을 찾았습니다. 데이터소스를 여러개 설정해 놓으면 @Transactional이 안 먹는 현상이었습니다. ( 리모트db 테스트와 jndi 테스트때문에 여러개 만듬..;;;)
@Bean(name = "FirstDatasource") @Profile("!jndi") @ConfigurationProperties("spring.datasource.nxmdb") public DataSource firstDatasource() { log.info("firstDatasource====="); return DataSourceBuilder.create() .type(HikariDataSource.class) .build(); }
---> 추가해야함.
@Bean(name = "transactionManager") @Primary public PlatformTransactionManager transactionManager() { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(firstDatasource()); return transactionManager; }
트랜잭션 매니저를 생성해주니 잘 동작합니다.
------------------------------------------------------------
리모트 db 트랜잭션
<!-- Spring Boot Starter JTA Atomikos --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> <version>2.7.12</version> <!-- Replace with the appropriate Spring Boot version --> </dependency>
oracle xa설정 sqlplus sys as sysdba grant select on sys.dba_pending_transactions to anytest; grant select on sys.pending_trans$ to anytest; grant select on sys.dba_2pc_pending to anytest; grant execute on sys.dbms_system to anytest; grant execute on dbms_xa to anytest; GRANT EXECUTE ON sys.dbms_system TO system; GRANT SELECT ON sys.dba_pending_transactions TO system; GRANT SELECT ON sys.dba_2pc_pending TO system; GRANT SELECT ON sys.pending_trans$ TO system; GRANT SELECT ON sys.dba_pending_transactions TO system;
application-local.yml spring: config: activate: on-profile: local jta: enabled: true nxmdb : datasource: jdbc-url: jdbc:oracle:thin:@localhost:1521/xe username: system password: root driverClassName: oracle.jdbc.OracleDriver anytest : datasource: jdbc-url: jdbc:oracle:thin:@localhost:1521/xe username: anytest password: nxcus2023 driverClassName: oracle.jdbc.OracleDriver db1: datasource: xa-data-source-class-name: oracle.jdbc.xa.client.OracleXADataSource xa-properties: user: system password: root url: jdbc:oracle:thin:@localhost:1521/xe db2: datasource: xa-data-source-class-name: oracle.jdbc.xa.client.OracleXADataSource xa-properties: user: anytest password: nxcus2023 url: jdbc:oracle:thin:@localhost:1521/xe server: port: 8808
package com.skcc.nxcus_spring.config; import com.atomikos.icatch.jta.UserTransactionImp; import com.atomikos.icatch.jta.UserTransactionManager; import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean; import org.springframework.context.annotation.*; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.jta.JtaTransactionManager; import javax.sql.DataSource; import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; import java.util.Properties; @Slf4j @Configuration @EnableTransactionManagement @MapperScan(value="com.skcc.nxcus_spring.mapper.nxmdb", sqlSessionFactoryRef="nxmdbSessionFactory") public class FirstDatasourceConfig { /* @Bean(name = "firstDatasource") @Profile("!jndi") @ConfigurationProperties(prefix = "spring.nxmdb.datasource") public DataSource firstDatasource() { log.info("originalDataSource====="); return DataSourceBuilder.create() .type(HikariDataSource.class) .build(); } @Bean(name = "firstDatasource") @Profile("jndi") public DataSource jndifirstDatasource() { log.info("jndifirstDatasource====="); JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup(); return jndiDataSourceLookup.getDataSource("OCBX01"); } / @Bean(name = "nxmdbSessionFactory") public SqlSessionFactory nxmdbSessionFactory(@Qualifier("firstDatasource")DataSource dataSource) throws Exception { log.info("nxmdbSessionFactory====="); SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setVfs(SpringBootVFS.class); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resource = resolver.getResources("mapper/.xml"); factoryBean.setMapperLocations(resource); factoryBean.setTypeAliasesPackage("com.skcc.nxcus_spring"); return factoryBean.getObject(); } @Bean(name = "nxmdbSqlSessionTemplate") public SqlSessionTemplate nxmdbSessionTemplate(SqlSessionFactory nxmdbSessionFactory) { log.info("nxmdbSessionTemplate====="); return new SqlSessionTemplate(nxmdbSessionFactory); } /* @Bean(name = "nxmdbTransactionManager") public PlatformTransactionManager nxmdbTransactionManager(@Qualifier("firstDatasource") DataSource dataSource) { log.info("nxmdbTransactionManager====="); DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } */ ////////////////////////////////////////////////////////////////////// @Value("${spring.db1.datasource.xa-data-source-class-name}") String ds1XaDataSourceClassName; @Value("${spring.db1.datasource.xa-properties.user}") String ds1User; @Value("${spring.db1.datasource.xa-properties.password}") String ds1Password; @Value("${spring.db1.datasource.xa-properties.url}") String ds1Url; @Bean(name = "firstDatasource") public DataSource dataSource() { log.info("db1DataSource AtomikosDataSourceBean"); AtomikosDataSourceBean ds = new AtomikosDataSourceBean(); ds.setUniqueResourceName(DS1_DATASOURCE); ds.setXaDataSourceClassName(ds1XaDataSourceClassName); Properties p = new Properties(); p.setProperty("user", ds1User); p.setProperty("password", ds1Password); p.setProperty("URL", ds1Url); ds.setXaProperties (p); return ds; } @Bean(name = "userTransaction") public UserTransaction userTransaction() throws Throwable { UserTransactionImp userTransactionImp = new UserTransactionImp(); userTransactionImp.setTransactionTimeout(10000); return userTransactionImp; } @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close") public TransactionManager atomikosTransactionManager() throws Throwable { UserTransactionManager userTransactionManager = new UserTransactionManager(); userTransactionManager.setForceShutdown(false); return userTransactionManager; } @Bean(name = "multiTxManager") @DependsOn({ "userTransaction", "atomikosTransactionManager" }) public PlatformTransactionManager transactionManager() throws Throwable { log.info("multiTxManager=PlatformTransactionManager==transactionManager=="); UserTransaction userTransaction = userTransaction(); JtaTransactionManager manager = new JtaTransactionManager(userTransaction, atomikosTransactionManager()); return manager; } }
package com.skcc.nxcus_spring.config; import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Profile; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; import java.util.Properties; @Slf4j @Configuration @MapperScan(value="com.skcc.nxcus_spring.mapper.anytest", sqlSessionFactoryRef="anytestSessionFactory") public class SecondDatasourceConfig { /* @Bean(name = "secondDatasource") @Profile("!jndi") @ConfigurationProperties("spring.anytest.datasource") public DataSource secondDatasource() { log.info("local or server"); return DataSourceBuilder.create() .type(HikariDataSource.class) .build(); } @Bean(name = "secondDatasource") @Profile("jndi") public DataSource secoundjndiDatasource() { JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup(); return jndiDataSourceLookup.getDataSource("OCBX"); } / @Bean(name = "anytestSessionFactory") public SqlSessionFactory anytestSessionFactory(@Qualifier("secondDatasource")DataSource ds) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(ds); factoryBean.setVfs(SpringBootVFS.class); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resource = resolver.getResources("mapper/.xml"); factoryBean.setMapperLocations(resource); factoryBean.setTypeAliasesPackage("com.skcc.nxcus_spring"); return factoryBean.getObject(); } @Bean(name = "anytestSqlSessionTemplate") public SqlSessionTemplate anytestSqlSessionTemplate(SqlSessionFactory anytestSessionFactory) { return new SqlSessionTemplate(anytestSessionFactory); } /* @Bean(name = "fepdbTransactionManager") public PlatformTransactionManager remoteTransactionManager(@Qualifier("secondDatasource") DataSource dataSource) { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } */ ////////////////////////////////////// public static final String DS2_DATASOURCE = "secondDatasource"; @Value("${spring.db2.datasource.xa-data-source-class-name}") String ds2XaDataSourceClassName; @Value("${spring.db2.datasource.xa-properties.user}") String ds2User; @Value("${spring.db2.datasource.xa-properties.password}") String ds2Password; @Value("${spring.db2.datasource.xa-properties.url}") String ds2Url; @Bean(name = "secondDatasource") public DataSource dataSource() { log.info("db2DataSource AtomikosDataSourceBean"); AtomikosDataSourceBean ds = new AtomikosDataSourceBean(); ds.setUniqueResourceName(DS2_DATASOURCE); ds.setXaDataSourceClassName(ds2XaDataSourceClassName); Properties p = new Properties(); p.setProperty("user", ds2User); p.setProperty("password", ds2Password); p.setProperty("URL", ds2Url); ds.setXaProperties (p); return ds; } }
@Transactional(rollbackFor = Exception.class, value = "multiTxManager") public int testTran(DatasetList dsList) { Dataset dsParam = DatasetUtil.getGdsParam(dsList); // Dataset을 SQL에 적용할 변수형인 Map으로 변환하면서 사용자 정보 입력 Map mapParam = DatasetUtil.getMap(dsParam, DatasetUtil.UPPER_CASE); log.info("aop class={}", codeMapper.getClass()); //트랜잭션이 활성화되었는지 확인 boolean txActive = TransactionSynchronizationManager.isActualTransactionActive(); log.info("tx active={}",txActive); int iRes1 = 0; iRes1 = codeMapper.updateTran1(mapParam); iRes1 = fepMapper.updateFep(mapParam); //리모트디비 iRes1 = codeMapper.updateTran2(mapParam); return iRes1; }
작성하니 세션도 db별로 1개씩 총 2개 생성되고 롤백도 잘 되네요.
1
DataSource 를 여러개 사용하는것 까지 하시다니 대단하시네요.
그리고, 덕분에 저도 이런 상황에 대한 지식을 얻었습니다.
제 강의를 보면서 Transaction 부분에 관심이 있으신분은 처음인것 같아요.
지극히 제 개인적인 기준으로 굳이 어떤 개발 레벨을 나눠야 한다면
그중 하나가 저는 DB 관리부분 특히 트랜잭션 부분에 대해 알고 있는가라고 생각해요.
실무에서 정말 크리티컬한 상황을 발생시키거든요.
덕분에 저도 공부하게되었습니다.
감사합니다.
0
안녕하세요.
좀더 정확한 내용파악을 위해서 codemap.updateTran1, codemap.updateTran2 메소드를 보면 좋을것 같습니다.
codemap 객체가 위에 올려준 메소드가 있는 클래스와 같은지 다른지도 궁금하네요.
아마도 다른 클래스의 객체이지 않을까 하는데요.
다른 클래스의 객체일때 Propagation 설정이 신규 세션을 맺도록 되어있지 않을까 생각도 해봅니다.
소스를 좀더 보여주시면 좀더 도움이 될 수 있을것 같습니다.
마이바티스 환경설정 조회하기 강의 부분에서 메뉴부분에러
0
58
2
자바 8버전이 선택지에 없는데 어떻게 하죠
0
71
2
zip파일 다운받아서 풀었는데도 계속 오류가 생기네요
0
182
2
가격 수정만 자꾸 에러페이지로 갑니다...ㅜ
0
266
2
오류가 이렇게 뜨는데
0
498
1
타임리프 > jsp
0
97
1
File imprt 어떤거 해야하죠?
0
127
1
검색기능이 안됩니다
0
142
2
검색기능이 안됩니다
0
173
3
500에러
0
168
2
v2 객체 만드는중 입니다
0
125
2
오류가 자꾸 나는데 왜이러는 걸까요?ㅠㅠ
0
239
5
오류가 왜 나는건지 모르겠어요
0
150
2
스프링 부트 버전
0
168
2
log.info가 적용이 안되는 문제
0
172
1
Spring Boot에서 jsp 연동 오류
0
317
1
7장 insert mapper erro 문의합니다
1
246
2
선생님 혹시 파일업로드도 알려주실수있나여?
2
593
1
선생님 혹시 세션하고 쿠키 부분 언제쯤 올려주실수있나여?
1
195
1
스프링 부트 2.x 버전 지원 중단, myBatis 추가가 안돼요
0
880
1
커뮤니티 버전에서 스프링 부트를 선택할수 없습니다.
1
347
1
안녕하세요 Ajax강의 잘듣고있습니다. 다름이 아니라 Ajax로 검색할떄 시작일이나 종료일 고객명과 같은 검색조건을 어떻게 구현해야하는지 고민을해보다 질문드립니다.
1
349
2
DB 생성시 발생 에러 관련! "Can't create table" "Error No 150. "Foreign key constraint is incorrectly formed")
1
527
0
int i = menuService.doInsert(coffee,kind,price); 이 코드 질문있어요
1
376
1

