TIL - 0715
java-ims
객체지향적으로 프로그래밍하기
- 상태값을 꺼내어 외부에서 작업하지말고, 메세지로 요청을 날리자
- path를 ControllerPool에 전달해서 ControllerPool이 원하는대로 작업을 하는게 아니라 path를 가진 Request에 요청할 수 있게 Request 객체만 전달해서 요청할 수 있게하기
- 매번 의식하는데 이런 사소한 부분에서 계속해서 객체지향적인 코딩을 하지못하네…. 계속 의식하면서 하기
/* 수정 전 */
public class ControllerPool<T extends Controller> {
.
.
.
public T search(String requestPath) {
.
.
.
}
}
/* 수정 후 */
public class ControllerPool<T extends Controller> {
.
.
.
public T search(Request request) {
String searchUri = request.getFirstUri();
.
.
.
String excludeParams = request.getUriExcludeParams();
}
}
- 또다른 예제코드
- user가 Level을 가지고 있고, Level에 요청을 해서 다음 레벨을 가져오면 될 것을 Level.SILVER 처럼 하드코딩으로 다음 레벨을 지정해주고 있음 - 다음 레벨이 신설되어SILVER가 아닐 경우는 어떻게? 그렇다면 Level 코드 뿐만 아니라 upgradeLevel 코드도 변경해야함(전혀 객체지향적이지않음 - 요청하자)
private void upgradeLevel(User user) {
// user.setLevel(Level.SILVER); 가 아니라
user.upgradeLevel(); // 얘로
}
public enum Level {
BASIC(SILVER),
SILVER(GOLD),
GOLD(null);
private final Level next;
public boolean hasNext() {
return Objects.nonNull(next);
}
public Level nextLevel() {
return next;
}
}
spring
트랜잭션 서비스 추상화로 알아보는 서비스 추상화 - 트랜잭션 알기
- 트랜잭션 : 여러개의 작업을 하나의 작업 단위(더이상 쪼갤 수 없음 - 원자성)로 묶음
- 하나로 묶인 작업을 처리하는 도중 에러가 발생한다면 실패로 처리하여 실행하던 작업으로 인해 발생한 변경 상태를 다시 처음으로 돌려버림(모두 성공하거나 모두 실패하거나)
- JDBC 트랜잭션 처리를 하기위해서는 트랜잭션 경계를 설정(커넥션을 가져오고 - 커넥션을 닫음까지)해야함 : 경계 내 코드는 하나의 작업으로 묶임(로컬 트랜잭션 : 커넥션 안에서 만들어짐)
- 로컬 트랜잭션을 생성하지않으면 각각이 독립적인 트랜잭션으로 실행 : 묶어서 처리해서 결과를 내어야하는데 개별적으로 처리하다보니 하나가 에러 발생해도 앞서 처리한 것은 그대로 반영(commit)
- 트랜잭션 처리 끝에서 commit()하면 데이터베이스에 반영 : 이후 다른 계층에서 에러(서버 다운 포함)가 발생해도 이미 데이터베이스에는 반영되어있는 상태
- JDBC 트랜잭션 경계 설정 코드
Connection conn = dataSource.getConnection();
conn.setAutoCommit(false);
try {
PreparedStatement ps1 = conn.prepareStatement("...");
PreparedStatement ps2 = conn.prepareStatement("...");
.
.
.
conn.commit();
} catch (Exception e) {
c.rollback();
}
conn.close();
- [갑자기 생각난 트랜잭션 어노테이션 위치가 서비스 계층인 이유] : 서비스 계층에 트랜잭션 코드를 둬야하는 이유
- 데이터베이스 액세스(DAO or Repository)계층에 두었을 때 단순히 액세스 코드만 트랜잭션 처리만 될 뿐 액세스 하기 전 비즈니스 로직에 포함된 코드들은 트랜잭션 처리가 되지않음, 데이터베이스 액세스 계층은 데이터베이스 액세스 작업만 할 뿐임(계층 나눴으면 계층 나눈대로 똑바로 시켜야함)
- 액세스 작업을 포함한 비즈니스 로직 자체가 트랜잭션 처리되어야함 : 로직을 거쳐 상태값이 변경되고, 변경된 상태값을 데이터베이스에 반영하는 것임
/* UserService.class */
@Transactional
public User update() {
userRepository.update(user);
}
java
enum 활용의 장점
- 고정값을 정의해둘 수 있음 : 값 중복 걱정은 안해도됨
- boundary가 생김 : 정의한 enum 타입의 인스턴스만 입력 받을 수 있음, int와 같이 기본 타입을 사용할 경우 컴파일러가 체크를 하지못하다보니 코드 상에서 처리를 해줘야함
public boolean exam(Level level) {
.
.
.
}
sql(use mysql)
데이터 갱신(삽입, 수정, 삭제)
- 삽입할 때 NOT NULL이 아니라면 생략가능함 : Default 값이 INSERT 됨
- VALUES 뒤로 “()”로 구분해서 한꺼번에 여러개의 데이터를 삽입할 수도 있음 : 쿼리문을 여러번 실행하지않고, 쿼리 1개로 처리해서 더 빨라질 수 있음
- 테이블을 복사하고, 원본 테이블로부터 복사본 테이블로 INSERT 할 수도 있음
> INSERT INTO MEMBER (MEMBER_ID, NAME) VALUES (1, 'colin');
> INSERT INTO MEMBER (MEMBER_ID, NAME) VALUES (1, 'colin'), (2, 'jinbro'), (3, 'imjinbro');
> CREATE TABLE MEMBER_COPY LIKE MEMBER;
> INSERT INTO MEMBER_COPY SELECT * FROM MEMBER;
- 수정할 때 조건절을 줘서 특정 row(행)만 변경되도록 할 수 있음, 그렇지않으면 모든 row에 대해 SET으로 설정한 COLUMN의 값이 변경됨(DEFAULT로 설정)
- 여러 column(열)의 값을 한꺼번에 변경하려면 SET 뒤의 column명을 여러개 지정하면 되는데 구분은 “,”로 구분함
- column의 기본값이 있을 때는 지정할 값에 DEFAULT 를 입력하면 기본값으로 수정됨
> UPDATE MEMBER SET NAME = 'imjinbro' WHERE MEMBER_ID = 4;
> UPDATE MEMBER SET NAME = 'imjinbro', TEAM_ID = 1 WHERE MEMBER_ID = 4;
> UPDATE MEMBER SET TEAM_ID = DEFAULT WHERE MEMBER_ID = 5;
- 삭제할 때 조건을 달지않으면 모든 row가 삭제됨
> DELETE FROM MEMBER;
> DELECT FROM MEMBER WHERE MEMBER_ID = 5;