기존에 JPA를 사용할 때 @Transactional을 사용해서

자동으로 커밋, 롤백을 처리하게 사용했다

 

그렇게 사용하는것이 스프링부트에서 권장하는 방법이지만

JDBC에서 직접 커넥션풀을 열고 닫고 또는 커밋 롤백 하듯이

JPA에서도 가능하다고 하기에 해보고자 한다

 

1. 개발 환경

- Java 17

- SpringBoot 2.7.14

- JPA

- Postgresql

- Maven

- IntelliJ

 

dependency

- spring-boot-starter-web

- spring-boot-starter-data-jpa

- spring-boot-devtools

- postgresql

- lombok

 

2. Properties

# DataSource configuration
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=
spring.datasource.username=
spring.datasource.password=

## Hibernate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.connection.autocommit=false

 

3. Controller

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MemberController {
	private final MemberService memberService;

	public MemberController(MemberService memberService) {
		this.memberService = memberService;
	}

	@PostMapping("/aaa")
	public String createMember(@RequestBody Member newMember) {
		String createMember = memberService.createMember(newMember);
		System.out.println(createMember);
		return createMember;
	}

	@PostMapping("/ttt")
	public String createMemberTransaction(@RequestBody Member newMember) {
		String createMemberTransaction = memberService.createMemberTransaction(newMember);
		System.out.println(createMemberTransaction);
		return createMemberTransaction;
	}
}

 

4. Service

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.transaction.Transactional;

import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class MemberService {

	// 엔티티 매니저 팩토리 객체 생성
	private final EntityManagerFactory emf;

	// 멤버 레포지토리 객체 생성
	private final MemberRepository memberRepository;

	public String createMember(Member newMember) {

		// 엔티티 매니저 객체 생성
		EntityManager em = emf.createEntityManager();

		// 트랜잭션 사용을 위한 객체 생성
		EntityTransaction transaction = em.getTransaction();

		try {
			// 트랜잭션 시작
			transaction.begin();

			// 엔티티 객체의 상태 변경
			em.persist(newMember);

			// 트랜잭션 커밋
			transaction.commit();

			return "Commit successful. New member created.";

		} catch (Exception e) {
			// 예외 발생 시 롤백
			transaction.rollback();

			return "Commit failed. Transaction rolled back.";

		} finally {
			// 엔티티 매니저 종료
			em.close();
		}
	}

	@Transactional(rollbackOn = Exception.class)
	public String createMemberTransaction(Member newMember) {

		// 멤버 중복 아이디 찾기
		Member existingMember = memberRepository.findById(newMember.getId()).orElse(null);

		// 중복 값 예외 처리
		if (existingMember != null) {
			throw new IllegalArgumentException("ID already exists: " + newMember.getId());
		}

		// 엔티티 객체의 상태 변경
		memberRepository.save(newMember);

		return "Commit successful. New member created.";
	}
}

 

5. Member

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
@Table(name = "member")
public class Member {
	@Id
	@Column(name="MEMBER_ID" ,nullable = false)
	private String id;

	@Column(name="MEMBER_NAME" ,nullable = false)
	private String memberName;

}

 

6. Repository

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MemberRepository extends JpaRepository<Member, String> {

}