'03.03.14 story JAVA이야기2010. 4. 1. 13:32
11 : 30 ~ 04:00 effective java
04 : 00 ~ 08:00 Oracle
08 : 00 ~ 10:00 Android
추상 클래스보다는 인터페이스를 사용하자
인터페이스는 안전하고 강력한 기능 향상을 가능하게 해준다.
전략을 표현할 때 함수 객체를 사용하자
중첩클래스에는 4가지 종류가 있다.
1. static멤버클래스
2. static이 아닌 멤버 클래스
3. 익명클래스
4. 지역클래스
만일 중첩클래스가 메소드 외붕서 접근할 필요가 있거나, 또는 코드가 너무 길어서 메소드 내부에 두기가 적합하지 않다면 멤버 클래스를 사용하자. 만일 멤버클래스의 각 인스턴스가외곽 클래스의 인스턴스를 참조할 필요가 있다면 static이 아닌 메버 클래스로 만들고, 그렇지 않다면 static으로 만든다.클래스가 어떤 메소드 내부에 속한다는 가정하에, 만일 한곳에서만 그 클래스의 인스턴스를 생성할 필요가 있고, 그 클래스의 특성을 나타내는 타입이 이미 존재한다면, 익명 클래스로 만들고 그렇지 않으면, 지역 클래스로 만든다.
하나 이상의타입 매개변수를 선언하고 있는 클래스나 인터페이스를 제네릭 클래스, 또는 제네릭 인터페이스라고 한다. 예를 들어, List인터페이스에는 하나의 타입 매개변수로 E가 있느네 여기서 E는 List에 저장되는 요소의 타입을 나타낸다. 이제부터는 그 인터페이스의 이름이 List<E>("E"리스트)지만, 줄여서 List라고 줄여 부르기도 한다.
제네릭 클래스와 인터페이스를 합해서 제네릭 타입이라고 부른다.
언바운드 와일드 카드 타입
제네릭 타입은 사용하고 싶지만 실 타입 매개변수를 모르거나, 어떤 타입이든 관계없다면 타입 대신 물음표를 사용하면 된다.
예를들어, 제네릭타입 Set<E>의 언바운드 와일드 카드 타입은 Set<?>이다.
요약하자면, 원천 타입을 사용하면 런타임 시 예외가 생길 수 있으므로 앞으로 작성할 새 코드에는 사용하지 말자.
원천 타입은 제네릭이 나오기 전에 작성된 기존 �와의 호환성과 상호 운용성을 위해서만 제공된 것이다.
Set<Object>은 매개변수화 타입으로써 어떤 타입의 객체도 포함할 수 있는 Set을 나타내며, Set<?>은 언바운드 와일드 카드 타입으로써 일부 미 지정 타입의 객체만을 포함할 수 있는 Set이다.
배열보다는 List를 사용하자.
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in";
//런타임시 에러 발생
List<Object> ol = new ArrayList<String>();
ol.add("I don't fit in");
//컴파일시 에러 발생
class DelayedQueue<E extends Delayed> implements BlockingQueue<E>;
<!-- E는 java.util.concurrent.Delayed 타입이라는 것을 명시적으로 선언함으로써 Delayed클래스의 메소드 이용할 수 있고, 별도의 캐스팅도 필요없으며, ClassCastException예외발생위험도 없다
이러한 E타입 매개변수를 바운드 타입 매개변수라고 한다.(즉, 명시적으로 이게 어떤 타입인지를 선언함) -->
타입 매개변수 목인 <E extends Delayed>는 DelayQueue에 저장되는 요소의 타입을 나타내는데 실 매개변수 E가 반드시 java.util.concurrent.Delayed 인터페이스의 서브 타입이어야 한다는 의미. 따라서 DelayQueue 클래스와 그 클래스의 클라이언트가 DelayQueue에 저장된 요소들의 Delayed메소드를 이용할 수 있으며, 별도의 캐스팅이 필요없고 ClassCastException 예외발생위험도 없다. 이러한 타입 매개변수를 바운드 타입 매개변수라고 한다.
요약하면, 클라이언트 코드에서 캐스팅을 해야 하는 타입보다 제네릭 타입이 더 안전하고 쓰기 쉽다. 새로운 타입을 설계할 때는 그런 캐스팅 없이 사용가능한지 꼭 확인하자. 캐스팅 없이 사용할 수 있다는 것은 해당 타입을 제네릭하게 만든다는 의미가 된다. 시간이 닿는 대로 기존 타입을 제네릭화하자. 그럼으로써 기존 클라이언트 코드에 영향을 주지않고 그 타입을 더욱 쉽게 사용할 수 있을 것이다.
제네릭 메소드를 애용하자.
사용방법
//제네릭화 해야 하는 것. 바람직 하지 않다.
public class GenericMethod{
public static Set Union(Set s1, Set s2){
Set result = new HashSet(s1);
result.addAll(s2);
return result;
}
}
//제네릭화 해보자
public static <E> Set<E> Union(Set<E> s1, Set<E> s2{
Set<E> result = new HashSet<E>(s1);
result.addAll(s2);
return result;
}
속성과 리턴유형 사이에 제네릭타입을 선언하고 선언되어있지 않은 Set객체에 제네릭 타입을 붙여준다.
제네릭 메소드 호출로 제공되는 타입 추론을 이용하여 매개변수화 타입의 인스턴스 생성 과정을 간편하게 할 수 있다. 제네릭 생성자를 호출할 때는 타입 매개변수의 값을 명시적으로 전달할 필요가 있는 이는 꽤 귀찮은 일이다. 타입 매개변수가 변수 선언 문장의 왼쪽과 오른쪽에 중복해서 나타나기 때문이다.
//생성자로 매개변수화 타입 인스턴스 생성하기
Map<String, List<String>> anagrams =
new HashMap<String, List<String>>();
이런 중복을 없애려면, 사용하고자 하는 각 생성자에 대응하는 제네릭 static 팩토리 메소드를 작성한다. 예를 들어, 매개변수가 없는 HashMap 생성자에 대응하는 제네릭 static 팩토리 메소드는 다음과 같다.
//제네릭 static 팩토리 메소드
public static <K,V> HashMap<K,V> newHashMap(){
return new HashMap<K,V>();
}
<DataBase>
Select Username,
V$lock.Sid, Trunc(Id1/Power(2,16)) Rbs,
Bitand(Id1,To_Number('ffff','xxxx'))+0 Slot,
Id2 Seq,
Lmode,
Request
From V$lock, V$session
Where V$lock.Type = 'TX'
And V$lock.Sid = V$session.Sid
and v$session.username = USER;
RBS, SLOT, SEQ = Transaction ID
Select Xidusn, Xidslot,Xidsqn
from v$transaction
XIDUSN, XIDSLOT, XIDSQN = Transaction ID
행은 하나의 트랜잭션만이 가질 수 있다.
블록은 여러 트랜잭션이 들어 올 수 있다.(MaxTrans 값에 따라 트랜잭션 수 결정)
예를들면 ,
update emp set sal = sal+10; 이면 emp테이블의 모든 블록의 모든 행에 대해 잠겨있다.
그러므로 다른 세션에서 emp테이블을 변경하려한다면 첫 번째 세션에서 행을 다 잠갔으므로, 두 번째 세션은 대기상태에 들어가게 된다. 만약
update emp set sal = sal+10 where ename like 'A%';//1번째 세션
update emp set sal = sal+10 where ename like 'B%'; //2번째 세션
이렇게 수행된다면 대기상태에 들어가지 않고 잘 수행된다.
동일 블록에 접근은 하지만 서로 다른 행에 잠금을 하므로 대기상태에 빠지지 않고 잘 수행됨
블록 클린아웃
여기서 한 가지 중요한 문제에 직면합니다. 만일 한 Transaction이 1,000만건의 Row를 변경한 후 Commit을 수행한다고 가정합니다. 1,000만개의 Row가 100만개의 Block에 저장되어 있다면 Oracle은 100개의 Block을 모두 다시 방문해서 Cleanout를 수행해야 합니다.
이것이 성능에 너무 치명적이기 때문에 Oracle은 "현재 Buffer Cache에 존재하는 Block 중 일부 Block들에 대해서만" Cleanout을 수행합니다. 이것을 Commit Cleanout이라고 부릅니다. Commit 시에 Cleanout이 이루어지지 않은 나머지 대다수의 Block들에 대해서는 나중에 이 Block을 Access(Read나 DML)하는 Process가 Cleanout을 수행합니다. 이것을 Delayed Block Cleanout이라고 부릅니다.
내 생각
블록 클린아웃의 개념은 매우 중요하다. 마법의 커밋이므로, 우리 커밋을 수행하면 디스크에 완전히 저장된 줄 안다. 하지만 그것은 착각이다.
블록 클린아웃에는 2가지가 있다. Commit Cleanout 과 Delayed Cleanout
만약, DML수행시 더티 블록이 버퍼캐시보다 작다면 Commit Cleanout으로 끝나지만,
DML수행시 더티 블록이 버퍼캐시보다 크다면 버퍼캐시만큼의 양만 Commit Cleanout되고 나머지의 블록들은 더티 블록으로 남아있게 된다. 그러므로 더티 블록에 대해서 질의를 하게 된다면 I/O작업이 발생하게 되고 수행시간은 사용자 입장에서 느려보일 수 밖에 없고, 이 현상에 이상하게 여겨 다시 질의해 보면 이미 블록은 클린 아웃되어있기에 문제점을 발견하기가 매우 힘들다. 그러므로 매우 많은 양의 DML을 수행하게 되었을 때, 관리자가 테이블은 한번 쭉 훑어주는게 낫다. Analyze 명령을 어차피 실행해야 하므로 이 방법으로 해결하자.
Snapshot too old!!!
롤백 세그먼트
20%80%
★★ snapshot too old 에러 발생과정
1. 20%정도 차 있었어.
2. 근데 트랜잭션이 절라 길어졌어 DML크기가 엄청 큼 90%
3. 두 개 합치면 110%
4.
10 20 80
초기에 있던 재실행로그를 덮어썻네?
5. 이 때, Rollback을 수행했어
6. 다시 초기에 있던 그대로 돌려놔야 해
7. 엥? 초기에 있던 데이터가 날라갔네
8. snapshot too old!!!
발생원인
1. 롤백 세그먼트 양이 너무작다.
2. 트랜잭션이 너무 길다.
3. 블록 클린 아웃
'JAVA이야기' 카테고리의 다른 글
'10.03.17 story (0) | 2010.04.01 |
---|---|
'10.03.16 story (0) | 2010.04.01 |
'10.03.15 story (0) | 2010.04.01 |
'03.03.13 story (0) | 2010.04.01 |
'03.03.12 story (0) | 2010.04.01 |