@Transactional 주의점
@Transactional은 생성된 객체의 처음 불린 method의 트랜잭션 상태를 유지한다.
동일 오브젝트 내에서 method 호출이 있을 때, 처음 호출 method에 @Transactional이 있으면 이후 호출된 메소드들도 모두 transaction 처리 되지만, 처음 호출된 method가 아닌 곳에서 @Transactional이 있을 때는 transaction 처리가 되지 않는다.
예제)
POM dependency
Data Schema
Mapper
Service
Main
위 코드에서 @Transactional이 UserService의 addUser()에 있으니 transaction 유지 되지만 @Transactional을 proxyAddUser()로 옮기면 처음 호출된 addUser가 @Transactional이 없기 때문에 전체가 transaction 없는 상태로 처리 된다.
int error의 주석을 풀어서 테스트 해보면, addUser()에 @Transactional이 붙어 있으면 roll-back 되지만, proxyAddUser()로 옮기면 roll-back 되지 않음.
출처: https://gs.saro.me/dev?page=6&tn=471
동일 오브젝트 내에서 method 호출이 있을 때, 처음 호출 method에 @Transactional이 있으면 이후 호출된 메소드들도 모두 transaction 처리 되지만, 처음 호출된 method가 아닌 곳에서 @Transactional이 있을 때는 transaction 처리가 되지 않는다.
예제)
POM dependency
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> |
Data Schema
1 2 3 4 5 6 7 8 9 10 11 12 | CREATE TABLE users ( no bigint NOT NULL auto_increment primary key, name character varying(64) NOT NULL ); CREATE TABLE user_data ( no bigint NOT NULL auto_increment primary key, name character varying(12) NOT NULL, value character varying(12) NOT NULL ); |
Mapper
1 2 3 4 5 6 7 8 9 10 11 | import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; @Mapper @Repository public interface UserDataMapper { @Insert("INSERT INTO user_data (name, value) VALUES (#{name}, #{value})") long addData(@Param("name") String name, @Param("value") String value); } |
1 2 3 4 5 6 7 8 9 10 11 | import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; @Mapper @Repository public interface UsersMapper { @Insert("INSERT INTO users (name) VALUES (#{name})") long addUser(@Param("name") String name); } |
Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import test.db.demo.mapper.UserDataMapper; import test.db.demo.mapper.UsersMapper; import java.text.SimpleDateFormat; import java.util.Date; @Component public class UserService { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); @Autowired private UsersMapper usersMapper; @Autowired private UserDataMapper userDataMapper; @Transactional public long addUser(String name) { return proxyAddUser(name); } public long proxyAddUser(String name) { String join_date = sdf.format(new Date()); long no = usersMapper.addUser(name); userDataMapper.addData("join_date", join_date); // int error = 0/0; return no; } } |
Main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @Slf4j @SpringBootApplication public class DemoApplication implements CommandLineRunner { @Autowired private UserService userService; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) throws Exception { log.info("유저추가: " + userService.addUser("abc")); } } |
위 코드에서 @Transactional이 UserService의 addUser()에 있으니 transaction 유지 되지만 @Transactional을 proxyAddUser()로 옮기면 처음 호출된 addUser가 @Transactional이 없기 때문에 전체가 transaction 없는 상태로 처리 된다.
int error의 주석을 풀어서 테스트 해보면, addUser()에 @Transactional이 붙어 있으면 roll-back 되지만, proxyAddUser()로 옮기면 roll-back 되지 않음.
출처: https://gs.saro.me/dev?page=6&tn=471
댓글
댓글 쓰기