위 블로그 보기) 이렇듯 serialVersionUID값을 파일등으로 저장을 할때 해당하는 클래스의 버전이 맞는지를 확인하는 중요한 장치입니다.
그런데 이 serialVersionUID를 작성하지 않으면 Java VM에서 내부 알고리즘에 따라서 자동으로 작성을 하게 되는데, 이것은 어떤 Java VM을 사용하는지에 따라서 달라지게 됩니다.
따라서 무조건 serialVersionUID 값을 설정하기를 권장을 합니다.
Points to remember:
1) static으로 선언되지 않은 변수들만 serialization 을 통해 저장이 된다.
2) Static 멤버와 transient 멤버는 Serialization을 할때 저장되지 않는다. 그래서 static으로 선언하지 않은 변수들 중에 저장하고 싶지 않은 내용은 무조건 modifier를 transient으로 만들어줘라.
3) 만약 부모 클래스가 Serializable 인터페이스를 implement했다면, 자식 클래스는 할 필요가 없다. 하지만 자식 클래스가 Serializable을 사용하고자 한다면, 부모 클래스는 무조건 Serializable 인터페이스를 먼저 implement해야만 subclass(자식)클래스가 사용할 수 있다.
4) 객체가 Deserialization을 거칠때 constructor는 실행되지 않는다.
5)
1. If a parent class has implemented Serializable interface then child class doesn’t need to implement it but vice-versa is not true. 2. Only non-static data members are saved via Serialization process. 3. Static data members and transient data members are not saved via Serialization process.So, if you don’t want to save value of a non-static data member then make it transient. 4. Constructor of object is never called when an object is deserialized. 5. Associated objects must be implementing Serializable interface. Example :
Serialization 과정에서 transient변수는 serialize가 안되고, deserialization과정에서 default 값으로 세팅이 된다. int는 0, 객체는 null로...)
Serialization 과정에서 static변수는 serialize가 안되고, deserialization과정에서 현재 상태의 클래스 멤버변수가 가지는 값으로 deserialize되어 세팅이 된다.
You have seen while deserializing the object the values of a and b has changed. The reason being a was marked as transient and b was static. In case oftransient variables:-A variable defined with transient keyword is not serialized during serialization process.This variable will be initialized with default value during deserialization. (e.g: for objects it is null, for int it is 0). In case ofstatic Variables:-A variable defined with static keyword is not serialized during serialization process.This variable will be loaded with current value defined in the class during deserialization.
transient keyword를 사용하는 이유는 serialization 과정에서 bytestream 단위로 변화시키는 것을 막기 위함이다. bytestream으로 변환이 안되면 파일에 저장이 안되게 할 수 있기 때문이다. 주로 정보 보안을 위해서 transient를 사용한다. 이 키워드를 사용하면 JVM에게 해당 변수는 persistent Java variable이 아니라는 것을 명시해준다.
이상하게 mapper.xml에서 sql 쿼리가 정상적으로 작동을 안하는지 결과가 엉뚱하게 테이블 내의 모든 row를 리턴해서 보여주고 있는 것이었다. 그리고 에러 메시지도 안뜨고...
내가 원하는건 딱 keyword를 포함하고 있는 게시글들이었는디...
참으로 답답했는데 다시 검색 기능 구현하기를 검색해본 결과 아래와 같이 코드를 변경해주니 정상 작동하였다. (감격 ㅠㅜㅜ)
요약:
like '%'||#{keyword}||'%' 부분을 -> CONCAT ('%', #{keyword},'%')
문제였던 구역: (전)
<!-- sql code 조각 -->
<!-- 반복되는 sql의 일부를 sql태그를 이용하여 따로 빼둘수 있다.
검색 조건 sql -->
<sql id="search">
<choose>
<!-- 검색옵션이 전체 검색일 경우 -->
<when test="searchOption == 'all'">
WHERE
writer like '%'||#{keyword}||'%'
OR
content like '%'||#{keyword}||'%'
OR
title like '%'||#{keyword}||'%'
</when>
<!-- 전체 검색이 아닐 경우 -->
<otherwise>
WHERE ${searchOption} like '%'||#{keyword}||'%'
</otherwise>
</choose>
</sql>
문제였던 구역: (후)
<sql id="search">
<choose>
<!-- 검색옵션이 전체 검색일 경우 -->
<when test="searchOption == 'all'">
WHERE
writer like CONCAT ('%', #{keyword},'%')
OR
content like CONCAT ('%', #{keyword},'%')
OR
title like CONCAT ('%', #{keyword},'%')
</when>
<!-- 전체 검색이 아닐 경우 -->
<otherwise>
WHERE ${searchOption} like CONCAT ('%', #{keyword},'%')
</otherwise>
</choose>
</sql>
board-mapper.xml 전체 코드
<mapper> 태그 안에 아래 코드:
<!-- 01. 게시글 전체 목록 조회 및 검색조회까지 -->
<select id="listAll" resultType="board">
SELECT*FROM
LF_Product_Test
<!-- 검색조건 -->
<include refid="search"></include>
ORDER BY seq
<!-- 페이징 -->
<!-- <include refid="pagingFooter"></include> -->
</select>
<!-- 02_02. 게시글 레코드 갯수 -->
<select id="countArticle" resultType="int">
SELECT COUNT(*) FROM LF_Product_Test
<!-- WHERE절을 include 태그로 삽입 -->
<include refid="search"></include>
</select>
<!-- sql code 조각 -->
<!-- 반복되는 sql의 일부를 sql태그를 이용하여 따로 빼둘수 있다.
검색 조건 sql -->
<sql id="search">
<choose>
<!-- 검색옵션이 전체 검색일 경우 -->
<when test="searchOption == 'all'">
WHERE
writer like CONCAT ('%', #{keyword},'%')
OR
content like CONCAT ('%', #{keyword},'%')
OR
title like CONCAT ('%', #{keyword},'%')
</when>
<!-- 전체 검색이 아닐 경우 -->
<!-- 따옴표 넣어줬는데 맞나...? -->
<otherwise>
WHERE ${searchOption} like CONCAT ('%', #{keyword},'%')
</otherwise>
</choose>
</sql>
$git merge feature master (컴공에서는 항상 A <- B 이런식이다) 즉, feature에 master를 갖다붙임
git merge가 git rebase에 비해 non-destructive method이라 여겨지는데, 왜냐하면 기존의 브랜치들이 영향을 받아서 바뀌지 않기 때문이다.
하지만, 이 방법은 master가 만약 active하게 계속 업데이트가 되는 상황이라면, 계속 feature브랜치가 새로운 커밋을 git merge해야하기 때문에 나중에 브랜치 히스토리를 복잡하게 만들 수 있다. git log 명령어로 조금 덜 복잡하게 만들 순 있지만 다른 개발자들에게 직관적인 브랜치 히스토리를 주지 못한다. (리뷰할때)
Rebasing
Merging의 대안으로rebasing 명령을 사용하여feature 브랜치를master브랜치로리베이스 할 수 있습니다.
git rebase를 하면 마치 순차적으로 master를 업데이트 하고 있던 것 처럼 보이게 만들 수 있습니다.
아래 그림과 같이 feature를 master 뒤에 연결함으로써 마치 처음부터 순차적으로(sequentially)하게 작업한 것과 같은 타임라인을 지니게 할 수 있습니다. 대신 commit history가 하나로 묶여지게 되죠. (마스터로 )
c3' 라는 복사본이 main의 위에 (main의 tip) 연결이 되고 c3는 희미하게 트리에 기록이 남아있습니다. 하지만 이 작업은 내 로컬 PC에만 작용이 된 것이기 때문에 remote에도 반영을 해줘야 합니다.
이렇게 main으로 checkout한 뒤에 rebase를 진행해줍니다.
그럼 아래 그럼과 같이 main과 bugFix가 같은 마지막 커밋 위치(HEAD)로 이동함을 알 수 있습니다.
즉, main이 앞으로 fast-forward되었습니다. (fast-forward는 아래 참조)
fast-forward란?
bugFix 브랜치를 만들고 작업하면서 그동안 master에 아무런 변화가 없었다면 master 브랜치의 HEAD를 bugFix 브랜치에 간단히 옮기기만(2가지 방법이 있음: git merge or git rebase) 해도 아무런 충돌없이 진행이 가능합니다. 그저 master 브랜치를 이동시키기만 해도 된다고 하여 fast-forward라고 부릅니다. 이동시키는 방법은 bugFix에서 $git rebase master 또는, $git merge master 를 하면 됩니다. 그럼 알아서 master의 HEAD를 옮기기만 합니다.
여기서는 내 정리)
하지만, 만약 master 브랜치가 계속 업데이트가 되어 바뀌었다면 fast-forward가 되지를 않습니다. 그래서 merge나 git rebase를 하게 되면 commit이 발생하게 되어 commit message를 입력하여야 합니다. 밑에 글 (스크롤 내려서) 참조: 서로 다른 브랜치 병합하기 부제목
Pull 을 해도 충돌 에러가 발생하면 아래와 같이 Synchronize 탭을 열어서 수동으로 코드를 병합해주고 (오른쪽이 remote에서 받아온 코드인데 이걸 왼쪽에 복붙해서 합쳐주고 저장) 이제 add to index -> commit (commit message 입력) -> pull 받으면 정상으로 해결이 된다.