회원 가입을 담당하는 RegistorController이다.
사용자이력을 다뤄야할 일이 생길경우(UserHistoryDao)
그러면 RegistorController에 주입을 해야한다. 즉 RegistorController가 바뀌어야한다.
이는 데이터베이스와는 상관이 없다. 회원가입할때 사용자 이력을 추가하는 것은 비즈니스 로직이다.
비즈니스 로직(Business logic)은 컴퓨터 프로그램에서 실세계의 규칙에 따라 데이터를 생성·표시·저장·변경하는 부분을 일컫는다. 이 용어는 특히 데이터베이스, 표시장치 등 프로그램의 다른 부분과 대조되는 개념으로 쓰인다.
비즈니스 로직은 이론적으로 3티어 구조에서 가운데 티어를 차지한다.
출처: 위키백과
프레젠테이션 계층
애플리케이션의 최상위 레벨은 사용자 인터페이스입니다. 인터페이스의 주요 기능은 작업과 결과를 사용자가 이해할 수 있는 것으로 변환하는 것이다.
논리 계층
이 계층은 애플리케이션을 조정하고 명령을 처리하며 논리적인 결정과 평가를 내리고 계산을 수행합니다. 또한 두 개의 주변 계층 간에 데이터를 이동하고 처리합니다.
데이터 계층
여기서 정보는 데이터베이스 또는 파일 시스템에서 저장 및 검색됩니다. 그런 다음 정보는 처리를 위해 논리 계층으로 다시 전달되고, 그 다음에는 사용자에게 다시 전달됩니다.
출처: 위키백과 https://ko.wikipedia.org/wiki/%EB%B9%84%EC%A6%88%EB%8B%88%EC%8A%A4_%EB%A1%9C%EC%A7%81
이는 데이터 베이스와는 상관이 없다. 왜냐하면 데이터베이스는 단순히 DB에 있는 테이블하고 1:1관계로 테이블을 다루는 곳이기 때문이다. UserDao에는 CRUD만 한다. 여기에 비지니스 로직을 들어가기에는 적합하지않다. 따라서 이는 Controller안에 들어가야한다. 그래서 Dao가 하나 추가가 되었다.
그러나
비지니스 로직이 바뀌었는데 Controller가 바뀐다. -> Controller역할은 비지니스 로직이 아니기때문에 적합하지않다.
따라서 비지니스로직을 다루는 계층이 하나더 필요하다.
비지니스로직을 DAO에 두지를 않는다.
UserService라는 새로운 객체를 만들고 이 객체에 Dao를 불러서 처리를 한다. 이곳에 Dao가 DI 된다. 그러면 Controller에서는 UserService만 주입받아서 쓰면 된다.
그러면
PrsenTation Layer
@Controller
Biz Logic
서비스 계층
UserService
Persistence layer
UserDao
UserHistoryDao
영속계층이라는 이유는 DB가 영속성을 가져서그렇다. (유지되는)
서비스계층(Biz Logic) 업무용어를 이용한다.(메서드 작성시)
만약 서비스계층에서 registerUser가 없다면 @Controller에서 UserDao하고 UserHistoryDao에 insert를 해야했다.
UserDao.insetUser()
UserHistoryDao.insetUser()
이런식으로 말이다. 이런 코드들이 @Controller에 들어가야했다. 근데 이 코드들을 BizLogic으로 옳기고 BizLogic부분에 registerUser()
라는 메서드를 만들고 그곳에 코드들을 집어 넣고
이 @Controller
은 registerUser()
만 호출하면 된다. 그러면 사용자를 등록할때 이 BizLogic 바뀔때 Method가 바뀐다. 그러나 @Controller
은 바뀌지 않는다. 왜냐하면 @Controller은 호출만 하면 되기때문이다.
즉 PrsenTation Layer은 바뀌지 않는다. -> 관심사의 분리가 성공적!
그리고 또 하나의 장점이 있다. 트렌젝션을 적용하기 위해서는 이 서비스 계층이 적합하다. 트랜젝션은 registerUser(User ~~)를 줬을때 userDao에 insert하고 userHistory에 insert할 것이다. 둘다 데이터베이스를 다루는 것이라 둘중하나라도 실패하면 안된다. 즉 트렌젝션이다. (두 개의 작업이 하나로 묶여야함) 그래야만 회원가입에 성공한다.
PrsenTation Layer에 들어가고 되지만 이러면 너무 복잡해지고 거대해진다.
애노테이션 정리
PrsenTation Layer
@Controller
Biz Logic
@Service
Persistence layer
@Repository
이 3개의 애노테이션은 모두 @Component를 포함하고 있다. 즉 <component-scan>
으로 자동스캔이 된다.
DAO의 각 메서드는 개별 Connection을 사용한다. 즉 메서드 마다 getConnection()를 사용해서 처리한다는 뜻이다. 따라서 메서드마다 개별적은 각각의 Connection이 만들어진다.
그러나 하나의 트렌젝션으로 처리될려면 하나의 커넥션으로 이루어져야한다. 그래서 TransactionManager이 필요하다. 같은 Transaction에 있으면 같은 Connection을 사용하게 만들어준다.
DAO에서 Connection을 얻거나 반환할 때 DataSourceUtils를 사용해야한다.
new DataSourceTransactionManager(ds)
이 부분은 TxManager 생성하는 부분이다.
new DefaultTransactionDefinition()
Tx의 속성을 정의하는 부분이다.
만약 a1Dao.inset의 함수 2개중 아무거나 에러가났다고 하면 예외발생을 시킨다. catch문으로 가서 rollback이된다. 즉 2개가 한개로 묶인다.
이를 수동으로 구현했지만
이렇게
bean으로 등록하면 쓰기 편해진다.
@Transactional은 AOP를 이용한 핵심 기능과 부가 기능의 분리를 해준다.
지금 이 코드들을 보면 분리를 해줘야한다.
@Transactional를 이용하면 다음과 같이 분리가 가능해진다.
핵심기능만 남아있는 것을 알 수 있다.
@Transactional은 클래스나 인터페이서에도 붙일 수 있다. 이렇게 되면 클래스내의 모든 메서드에 적용이 가능해진다.
그림 출처: https://github.com/castello/spring_basic/tree/main/download/%EA%B0%95%EC%9D%98%EC%9E%90%EB%A3%8C