Hibernate 를 사용하다가

HibernateException – A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance

의 오류를 발견했다. 인터넷을 뒤지다가 이에 대한 해결책을 찾아내었다.


본문을 보면 이런 내용이 나온다.

Your likely problem

Looks like you have a Parent entity and a Child entity. The Parent has a collection of Child entities with cascade=”all-delete-orphan”.

You are setting a new collection via the setter thus leaving the original collection unreferenced by the Parent entity. This doesn’t fly well with Hibernate and leaves it confused about what to do.

parent.setChilden(new HashSet<Child>()); // This won’t work. Could be an ArrayList too.

parent.getChildren().clear(); // There, fixed that!

So generally speaking, just clear out the old collection, rather than dereferencing it and creating a new one.

정리를 해보면, 필드에 새로 생성된 빈 Set 객체를 넣으려고 할 때 문제가 발생을 하는데,

초기화하려고 하는 Set 객체에서 clear() 메소드를 호출해주면 된다는 것이다. 


관계정의 옵션으로 

orphanRemoval=true, cascade=CascadeType.ALL

의 관계가 주어졌을 때 나타나는 증상으로 보인다.

회사에서 업무를 위해 DB에 저장하는 기초데이터 중 우편번호와 관련된 데이터는 빅데이터가 아닐까? 입려된 데이터의 건수로는 대략 6백7만건에 달하는 양이라서, insert 쿼리의 용량만 2기가에 달하는 녀석이기도 하다. 그래서 몇일간 데이터를 넣고 빼고하면서 

조금 더 빠르게 넣을 수 있는 방법이 없을까?

하고 고민을 하다가 mysql big data fast import 의 키워드로 검색을 하다보니 mysqldump로 하는 게 좋다는 이야기가 나오고 있어서 한번 찾아봤다.

찾아서 해보니... 600만건의 자료를 추출하는데 대략 10분, 넣는데 6분 정도의 시간이 소요되었다. 오홍... +_+)


참고사이트 : http://www.abbeyworkshop.com/howto/lamp/MySQL_Export_Backup/index.html

  • export 하기 : mysqldump 를 이용한 예

    • 데이터베이스 전체를 추출하는 경우
      mysqldump guestdb > guestdb.txt
    • 특정 테이블만 추출하는 경우
      mysqldump guestdb guestTbl > guestdb.txt
    • 특정 테이블에 대한 drop sql 을 추가하려는 경우
      mysqldump -p –user=username –add-drop-table guestdb guestTbl > guestTbl.txt
      Enter password: ********
  • import 하기

    • 데이터베이스 전체를 추출한 경우
      $ mysql -u username -p < guestdb.txt’
    • 특정데이터베이스의 테이블만 추출한 경우
      $ mysql -u username -p –database=guestdb < guestTbl.txt


참고사이트 : http://www.zparacha.com/remove-eclipse-workspace-dropdown-list/#.T7sxfHl1BRU

이클립스에서 Switch workspace를 자주 사용하다보면 현재 사용하지 않는 목록까지도 그대로 유지가 되면서 길어지는 경향이 있다. 이런 경우에 이클립스를 재설치를 하는 경우가 종종 있는데, 그러지 말고, 설정파일을 수정하여 가볍게 변경하도록 하자.


switch workspace 가 저장되어 있는 파일 위치

- 이클립스 설치위치//configuration/.settings/org.eclipse.ui.ide.prefs

이 파일 안에 변경했던 workspace 목록이 저장되어 있다.

MAX_RECENT_WORKSPACES=5

RECENT_WORKSPACES=/Users/ihoneymon/Documents/githubWorkspace/ipams\n/Users/ihoneymon/Documents/workspaces/dipams\n/Users/ihoneymon/Documents/workspaces/dreaminfra

RECENT_WORKSPACES_PROTOCOL=3

SHOW_WORKSPACE_SELECTION_DIALOG=false

eclipse.preferences.version=1

RECENT_WORKSPACES 에 길게 나열된 문자열 중에서 불필요한 부분을 제거하면 된다. \n 단위로 삭제하면 된다.


 

 이번달의 첫날과 마지막날 알아내기  

 

5월의 시작하는 날과 마지막날을 알아내는 것을 가정해본다.

var startDayOfMay = new Date(2012, 4, 1);

var endDayOfMay = new Date(2012, 5, 0);

console.log("startDayOfMonth : " + startDayOfMay + ", endDayOfMonth : " + endDayOfMay);


>> 결과

 startDayOfMonth : Tue May 01 2012 00:00:00 GMT+0900 (KST), endDayOfMonth : Thu May 31 2012 00:00:00 GMT+0900 (KST)



   생성한 Date 객체에서 월(Month)의 값을 꺼내면 어떤 값이 나올까?  
 

var today = new Date();

console.log("Date : " today + ", Month : " +today.getMonth());

>> 결과

Date : Tue May 15 2012 16:26:13 GMT+0900 (KST), Month : 4


출력된 Date 문자열은 분명 5월(May)를 나타내고 있는데, Date 객체에서 추출한 Month는 4가 나타났다.

이렇게 나타나는 이유는 자바스크립트의 Date 객체에서 월Month 가 0부터 시작하기 때문이다.

0 = 1월, 1 = 2월, 2 = 3월, ..., 10 = 11월, 11 = 12월.


확인하는 방법은 간단하다.

var modifyDate = new Date(2012, 0, 1); 
console.log("Date : " modifyDate + ", Month : " + modifyDate.getMonth());
>> 결과 
Date : Sun Jan 01 2012 00:00:00 GMT+0900 (KST), Month : 0

var modifyDate = new Date(2012, 11, 1); 
console.log("Date : " modifyDate + ", Month : " + modifyDate.getMonth());
>> ru
Date : Sat Dec 01 2012 00:00:00 GMT+0900 (KST), Month : 11


 

 왜 0부터 시작할까?  

 

참고 : http://www.evotech.net/blog/2007/07/javascript-date-object/

위의 사이트로 가보면, 마지막 Date.prototype... 코드 부분에 월Month을 배열Array로 처리하는 것을 확인할 수 있는데, 컴퓨터에서 사용하는 배열의 순서Index는 0부터 시작한다는 것을 생각해보면 어느정도 유추해볼 수 있을 듯 하다. getMonth()를 하면 객체가 속한 달의 순서Index값을 내놓는 것이라 생각해볼 수 있을 것 같다.



위 현상은 IE에서는 나타나지 않는다. 크롬브라우저에서만 나타난다.

 

 문제가 생기는 이유 : 

 

응답헤더에 ContentType 이외에 파일정보를 Header에 추가하는 코드 때문에 나타는 증상이다.  Internet Explore에서는 다운로드에 대한 파일정보를 헤더에 넣어줘도 이상이 없었지만, 크롬에서는 그것을 취약점 공격을 위한 수단으로 판단한 것으로 보인다. 

예제 코드 : 

HttpServletResponse response = (HttpServletResponse) ActionContext.getContext().get(StrutsStatics.HTTP_RESPONSE); response.setContentType("application/octet-stream; charset=utf-8"); try { //다운로드되는 파일의 정보를 헤더에 추가하는 코드 response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(item.getName(), "utf-8") + ";"); } catch (UnsupportedEncodingException ignored) { // do nothing }


 

 해결방법 : application/x-download 를 활용

 

해결 코드 :

HttpServletResponse response = (HttpServletResponse) ActionContext.getContext() .get(StrutsStatics.HTTP_RESPONSE); response.setContentType("application/x-download"); try { HttpServletRequest request = (HttpServletRequest) ActionContext.getContext() .get(StrutsStatics.HTTP_REQUEST); LOG.debug("User-Agent : " + request.getHeader("User-Agent")); if(request.getHeader("User-Agent").contains("Firefox")) { response.setHeader("Content-Disposition", "attachment;filename=\"" + new String(item.getName().getBytes("UTF-8"), "ISO-8859-1") + "\";"); } else { response.setHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(item.getName(), "utf-8") + "\";"); } } catch (UnsupportedEncodingException ignored) { // do nothing } response.setHeader("Content-Transfer-Encoding", "binary"); LOG.debug("Content-Disposition : " + response.getHeader("Content-Disposition")); LOG.debug("Content Type : " + response.getContentType()); File file = new File(item.getPath()); FileInputStream fileIn = null; ServletOutputStream outstream = null; try { fileIn = new FileInputStream(file); outstream = response.getOutputStream(); byte[] outputByte = new byte[8192]; while (fileIn.read(outputByte, 0, 8192) != -1) { outstream.write(outputByte, 0, 8192); } outstream.flush(); } catch (FileNotFoundException e) { LOG.error(e); } catch (IOException e) { LOG.error(e); } finally { try { fileIn.close(); } catch (IOException e) { } try { outstream.close(); } catch (IOException e) { } }



인터넷을 뒤져봤지만, 쉼표(,)를 다른 문자로 대체하면 된다는 해결책 외에는 딱히 방법이 없었다.

구글을 돌아디나다가 검색해서 찾은 해결책을 기록한다.

출처 : http://stackoverflow.com/questions/2405568/java-webapp-adding-a-content-disposition-header-to-force-browsers-save-as-beh

익스플로러8, 크롬(18.0.1025.151), 파이어폭스(11)에서 정상 동작합니다.

+ Recent posts