Mini

회원 서비스 개발 //의존관계주입, @Transactional(readOnly) 본문

Java/Spring-app

회원 서비스 개발 //의존관계주입, @Transactional(readOnly)

Mini_96 2023. 6. 6. 23:33

@Transactional(readOnly=true)

읽기전용모드 => 속도up

문제:쓰기가안됨

해결:쓰기해야되는 메소드위에 @Transactional(readOnly=false)

package jpabook.jpashop.service;

import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service    //component scan => 자동으로 스프링빈으로 등록해줘
@Transactional(readOnly = true) //JPA 데이터변경은 트랜잭션안에서해야. public Method에 적용됨. 읽기전용모드=>성능향상
public class MemberService {

    @Autowired  //자동주입해줘
    private MemberRepository memberRepository;

    //회원가입
    @Transactional(readOnly = false)  // 얘는 읽기전용아님.(기본값)
    public Long join(Member member){
        validateDuplicateMember(member);    //중복회원검사
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        List<Member> findMembers = memberRepository.findByName(member.getName());
        if(!findMembers.isEmpty()){
            throw new IllegalStateException("이미 존재하는 회원입니다");
        }

    }

    //회원 전체 조회
    public List<Member> findMembers(){
        return memberRepository.findAll();
    }

    public Member findOne(Long memberId){
        return memberRepository.findOne(memberId);
    }
}

 

*중복이름 검증

문제 : 멀티쓰레드에서 A, A 2명이 동시에 table등록함. -> 그시간에 검증통과함. -> ??

해결 : DB에 멤버이름에 unique 제약조건달아라. 

 

* @Autowired

1. 필드주입

@Autowired  //자동주입해줘
    private MemberRepository memberRepository;

단점: 테스트시 변경불가, 접근불가

해결:Setter 인젝션

2.Setter 인젝션

    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

단점 : app 동작후에는 이미 조립이 끝나기 때문에 바꿀일이 잘 없음.

 

3. 생성자 주입

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

장점 : main에서 new MemberService(파라미터 빠뜨리면) 하면 값넣어주라고 빨간줄 뜸.

팁 : 생성자1개 -> @Autowired 없어도 자동으로 달아줌.

 

4. 생성자 주입 + final field

    private final MemberRepository memberRepository;

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

장점 : 생성자 빠뜨리면(this.~~~) 빨간줄뜸

 

5. +

@RequiredArgsConstructor

장점 : final field 만 가지고 생성자 만들어줌.

기존코드:

    private final MemberRepository memberRepository;

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

최종코드 :

@RequiredArgsConstructor
public class MemberService {

    private final MemberRepository memberRepository;

 

6. MemberRepository도 적용

@RequiredArgsConstructor
public class MemberRepository {

    //@PersistenceContext //EntityManager만들어서 주입해줘
    private final EntityManager em;

※ @Autowired field -> @PersistenceContext 자동 달아줌.

 

* 최종 MemberRepository

package jpabook.jpashop.repository;

import jpabook.jpashop.domain.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;

@Repository //component scan => 자동으로 스프링빈으로 등록해줘
@RequiredArgsConstructor
public class MemberRepository {

    //@PersistenceContext //EntityManager만들어서 주입해줘
    private final EntityManager em;

    public void save(Member member){
        em.persist(member); //JPA야 저장해줘.
    }

    public Member findOne(Long id){
        Member member = em.find(Member.class, id);  //(클래스, id(키))주면 알아서 JPA가 찾아줌
        return member;
    }

    public List<Member> findAll(){
        return em.createQuery("select m from Member m",Member.class).getResultList();
                                                            //(쿼리,반환타입)를 리스트로만들어줘
    }

    public List<Member> findByName(String name){
        return em.createQuery("select m from Member m where m.name= :name",Member.class)    //:name 은 파라미터바인딩
                .setParameter("name",name)
                .getResultList();
    }

}

* 최종 MemberService

package jpabook.jpashop.service;

import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service    //component scan => 자동으로 스프링빈으로 등록해줘
@Transactional(readOnly = true) //JPA 데이터변경은 트랜잭션안에서해야. public Method에 적용됨. 읽기전용모드=>성능향상
@RequiredArgsConstructor
public class MemberService {

    private final MemberRepository memberRepository;

    //회원가입
    @Transactional(readOnly = false)  // 얘는 읽기전용아님.(기본값)
    public Long join(Member member){
        validateDuplicateMember(member);    //중복회원검사
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        List<Member> findMembers = memberRepository.findByName(member.getName());
        if(!findMembers.isEmpty()){
            throw new IllegalStateException("이미 존재하는 회원입니다");
        }

    }

    //회원 전체 조회
    public List<Member> findMembers(){
        return memberRepository.findAll();
    }

    public Member findOne(Long memberId){
        return memberRepository.findOne(memberId);
    }


}