예전에 ivy를 사용한 경험이 있는데 요새 뉴스거리에 가끔 maven이 올라 오길래 검색해보았다.
maven을 사용해 본 경험이 없어 비교하기가 그랬으나 누군가 경험적 비교를 해놔서 살펴보니..

난 ivy가 좋을 것 같다...
우스갯소리로 ivy는 dependency 추가가 한줄인데 maven은 5줄이상이다... 여기에서 부터 호불호가 갈렸다;;



경험을 바탕으로 간단히.. maven(maven2) vs ivy 장단점 비교를 해보겠습니다.

-  의존성 다운로드
1) ivy : 선택에 의해서 다운로드 가능. 해당 jar외엔 아무것도 받지 않겠다라고 쓸 수 있음. 명시적인 lib 관리 가능
2) maven : 불필요한 jar도 다운받을 수 있습니다. 쓰지 않더라도 선언때문에 다운 받을 수 있고, 상황에 따라서는 exclude 해줘야 함. 
(운영상..  maven을 못 쓴 이유가 바로 이런 불편함이었습니다. 쉽게 운영을 위해서는 명시적인 lib 외엔 다른 것을 쓰지 않도록 하는 것이 더 편리하고 명확합니다. )

- 라이브러리 경합
1) ivy : 유연성 제공, 같은 라이브러리, 버젼일 때, conflict manager 사용가능
2) maven : 같은 라이브러리라도 다른 버젼이면 맨 처음 선언된 artifact에 맞춰 다운로드 됩니다. maven plugin에서는 이 부분이 달라진다.. 결국 버젼 관계를 설정할 방법이 없습니다.

- 의존성 lib 기술 방법
1) ivy : property 이용. 
2) maven : element 단위.

- 이클립스 상
1) ivy : jar만 다운받으면, ant 상에서 빌드 가능, 플러그인 설치 필요 없음
2) maven : m2 플러그인 설치를 통해서 빌드 해야 함

- 장점
1) ivy : ant와 동시에 쓰면서 세밀한 작업이 가능함. 디렉토리 위치를 편하게 관리. 복잡해질 수 있는 소지. ant 의 condition 같은 구린 것이 if / else로도 쓸 수 있도록 지원.
2) maven : 플러그인을 편하게 쓸 수 있음. 간단한 구조에 좋음.

- ivy의 단점 : 파일 이름에 명시적인 패턴을 요구 합니다.


* ant + ivy는 spring 3 에서 사용하고 있습니다. 그 외에서 reference하는 곳는 많지는 않은 듯 합니다.


* 경험상..
maven은 작은 모듈에 적합
ant+ivy는 배포서버나, 세밀함이 필요한 곳에 적합


<볼만한 ivy 이야기>
  • item : forEach내에서 각 아이템 이름으로 사용할 것.
  • index : index
  • collection="classNames"  // 배열명
  • open=""  // forEach 시작 전 ex: "(" forEach 시작전에 ( #{item}
  • separator=","  // forEach 1회시 구분 해줄 기호
  • close="" // forEach 종료 후 ex: ")" forEach 종료 후에 ( #{item}, #{item}, #{item} .... #{item[index]} )



  
	SUM(CASE WHEN R.CLASS_NAME = #{item}  THEN R.CNT ELSE 0 END) AS #{item}



'백엔드 > myBatis' 카테고리의 다른 글

프로시저 호출 시 주의 할 점..  (0) 2012.11.13
iBatis isEqual  (0) 2012.11.05
[3.0] forEach 사용  (0) 2010.07.15
[3.0] like 검색.  (0) 2010.07.09
[3.0] JDBC Type  (0) 2010.07.09
iBatis 3.0 Cache 문제 -  (0) 2010.07.08
참조 : http://hmjkor.tistory.com/176
	
		
		 
		
		
		
		
		
		
		
		

'백엔드 > Spring' 카테고리의 다른 글

Spring 3.2.3 + myBatis 3.2.2  (0) 2013.07.19
Spring Framework 3.2.3 Maven으로 한번에 추가하기..  (0) 2013.07.18
Spring 3.2.2 + Tiles 3.0  (0) 2013.05.22
Spring Security 설정.  (2) 2011.08.30
[2011-05-26] Spring Security 설정 오류.  (0) 2011.05.26
MySQL AutoReconnect 설정.  (0) 2010.07.12
- iBatis 3.0 에서 간단하게 like 검색 하는 법

CB.CUSTOMER_NAME like CONCAT('%', #{customerName:VARCHAR}, '%')

사용 예 )
<-select id="expired_search" parametertype="java.util.HashMap" resulttype="net.autobrain.domain.ExpiredSearchResult" flushcache="false" usecache="false">
SELECT CB.COUPON_BOOK_NO, CN.COUPON_NAME_SEQ, CN.COUPON_NAME
		    , CASE WHEN CB.CHARGE_TYPE = 'F' THEN '무상' ELSE '유상' END AS CHARGE_TYPE
		    , AM.AUTO_MODEL_SEQ
		    , AM.MODEL_NAME
		    , IFNULL(CB.CAR_NUMBER, '') AS CAR_NUMBER
		    , CB.VIN_NO
		    , CB.CUSTOMER_NAME
		    , CONCAT(CB.CUSTOMER_PHONE_1, '-', CB.CUSTOMER_PHONE_2, '-', CB.CUSTOMER_PHONE_3) AS CUSTOMER_PHONE
		    , CB.AUTO_SALES_USER_SEQ
		    , SU.USER_NAME
		    , CB.COUPON_EXPIRED_DATE
		FROM COUPON_BOOK CB
		    INNER JOIN COUPON CP ON CP.COUPON_BOOK_SEQ = CB.COUPON_BOOK_SEQ
		    INNER JOIN COUPON_BOOK_SETUP CBS ON CBS.COUPON_BOOK_SETUP_SEQ = CB.COUPON_BOOK_SETUP_SEQ
		    INNER JOIN COUPON_NAME CN ON CN.COUPON_NAME_SEQ = CBS.COUPON_NAME_SEQ
		    INNER JOIN COUPON_SETUP CS ON CBS.COUPON_BOOK_SETUP_SEQ = CS.COUPON_BOOK_SETUP_SEQ
		    INNER JOIN AUTO_MODELS AM ON CBS.AUTO_MODEL_SEQ = AM.AUTO_MODEL_SEQ
		    INNER JOIN AUTO_CLASSES AC ON AM.AUTO_CLASS_SEQ AND AC.AUTO_CLASS_SEQ
		    INNER JOIN SALES_USERS SU ON SU.SALES_USER_SEQ = CB.AUTO_SALES_USER_SEQ
		    INNER JOIN SHOWROOM_CODES SC ON SU.SHOWROOM_SEQ = SC.SHOWROOM_SEQ
		WHERE CB.REFUND_DATE IS NULL AND CB.DISABLE IS NULL
		AND CN.COUPON_NAME_SEQ = #{couponNameSeq}
		AND CB.CUSTOMER_NAME like CONCAT('%', #{customerName:VARCHAR}, '%')
	        AND DATE_FORMAT(#{beginCriterionDate}, '%Y-%m-%d') <= DATE_FORMAT(DATE_SUB(CB.COUPON_EXPIRED_DATE, INTERVAL #{gubun} DAY), '%Y-%m-%d')
		AND DATE_FORMAT(DATE_SUB(CB.COUPON_EXPIRED_DATE, INTERVAL #{gubun} DAY), '%Y-%m-%d') <= DATE_FORMAT(#{endCriterionDate}, '%Y-%m-%d')
		AND (TO_DAYS(CB.COUPON_EXPIRED_DATE) - TO_DAYS(CAST(#{criterionDate} AS DATE)) BETWEEN #{criterionDay1:NUMERIC} AND #{criterionDay2:NUMERIC})
		GROUP BY COUPON_BOOK_NO
    <-/select>

'백엔드 > myBatis' 카테고리의 다른 글

프로시저 호출 시 주의 할 점..  (0) 2012.11.13
iBatis isEqual  (0) 2012.11.05
[3.0] forEach 사용  (0) 2010.07.15
[3.0] like 검색.  (0) 2010.07.09
[3.0] JDBC Type  (0) 2010.07.09
iBatis 3.0 Cache 문제 -  (0) 2010.07.08

쿼리~~
AND (TO_DAYS(CB.COUPON_EXPIRED_DATE) - TO_DAYS(CAST(#{criterionDate} AS DATE)) BETWEEN #{criterionDay1:NUMERIC} AND #{criterionDay2:NUMERIC})


'백엔드 > myBatis' 카테고리의 다른 글

프로시저 호출 시 주의 할 점..  (0) 2012.11.13
iBatis isEqual  (0) 2012.11.05
[3.0] forEach 사용  (0) 2010.07.15
[3.0] like 검색.  (0) 2010.07.09
[3.0] JDBC Type  (0) 2010.07.09
iBatis 3.0 Cache 문제 -  (0) 2010.07.08

1. Query 실행 후 그 결과를 Map에 담아 리턴해 페이지에 출력.
2. 다른 곳에서 위 출력 결과에 영향을 주는 컬럼 값을 변경한다. 
3. 다시 1번을 수행하면 2번의 결과가 반영되지 않고 수정하기 전의 결과가 딱 나온다.

iBatis로그가 아닌 일반 로그에서는 호출은 되나 iBatis가 실행되진 않았다.

- 조건을 다르게 해서 실행 했을경우 sql을 실행하지만, 결과 값인 Map에는 수정하기 전의 정보가 들어있다.
- statementType="CALLABLE" flushCache="false" useCache="false" 모두 헛 수고

왜 그런지 문서좀 뒤져야겠다..

일단.. iBatis 로그부터 찍어야하고..

'백엔드 > myBatis' 카테고리의 다른 글

프로시저 호출 시 주의 할 점..  (0) 2012.11.13
iBatis isEqual  (0) 2012.11.05
[3.0] forEach 사용  (0) 2010.07.15
[3.0] like 검색.  (0) 2010.07.09
[3.0] JDBC Type  (0) 2010.07.09
iBatis 3.0 Cache 문제 -  (0) 2010.07.08

description : only one may be defined as writable all others must be specified read-only

Many To One 매핑에서 자주 발생하는 문제이다..
또한 추가적으로 One쪽 PK가 Many쪽에서도 PK로 사용된다면 JPA 초기 설정된 상태로는 100% 에러난다.

A와 B의 관계가 N:1이면 A와 B의 PK들은 아래의 구조를 가지게 된다.


	//MasterCodes.java (A와 B의 관계에선 A, 즉 Many 쪽 table)
	@EmbeddedId
	private MasterCodesPK id; //복합키

	@Column(name="CODE_NAME")
	private String codeName;

	//생략~~

	//bi-directional many-to-one association to MasterCodeGroups
	@ManyToOne(cascade = REFRESH)
	@JoinColumn(name="CODE_GROUP_SEQ")
	private MasterCodeGroups masterCodeGroup;
	
	// getter / setter 생략~
	//MasterCodeGroups.java (A와 B의 관계에선 B, 즉 One에 해당)
	@Id
	@Column(name="CODE_GROUP_SEQ")
	@GeneratedValue(generator = "MASTER_CODE_GROUPS")
	private int codeGroupSeq;

	@Column(name="CODE_GROUP_NAME")
	private String codeGroupName;

	// 생략~~

	//bi-directional many-to-one association to MasterCodes
	@OneToMany(mappedBy="masterCodeGroup", cascade = REFRESH)
	private Set masterCodes;

	// getter - setter 생략~


위 내용이 JPA로 Table에서 불러와 세팅 된 것인데 이대로 했다가 에러가 빵 뜨더라..;;
그 에러가 제목과 같은 에러인데 -
복합키로 구성될 경우 자신의 PK가 아닌 다른 Table의 PK를 변경할 수 있다면? 있을수 없는 일이다;;
즉 A와 B에서 A의 키는 A_PK, B_PK를 사용하는데 A테이블에서 B_PK를 변경할 수 있다면? 무결성이 깨지게 된다.;;
이때는 차라리 B에서 B_PK가 변경된다면 A에서도 B_PK가 변경되게 제약 조건을 설정하는게 좋다 -

그래서 read-only로 하라는 에러가 나오는 것인데 -

아래와 같이 A테이블에 설정을 더 적어 주어야 한다..


	//MasterCodes.java (A와 B의 관계에선 A, 즉 Many 쪽 table)
	@EmbeddedId
	private MasterCodesPK id; //복합키

	@Column(name="CODE_NAME")
	private String codeName;

	//생략~~

	//bi-directional many-to-one association to MasterCodeGroups
	@ManyToOne(cascade = REFRESH)
	@JoinColumn(name="CODE_GROUP_SEQ", nullable=false, insertable=false, updatable=false)
	private MasterCodeGroups masterCodeGroup;
	
	// getter / setter 생략~



아까와 동일하나 JoinColumn Annotation에 기타 속성이 잔뜩 들어갔다;; 저렇게하면 read-only가 된다.

시간이 없어서 문서를 다 읽어보지 않고 중요 부분만 읽은 후에 썼는데 -
시간 있으신 분은 아래 사이트에서 다 읽어보면 좋을 것 같다.

http://trycatchfinally.blogspot.com/2006/01/mapping-relationships-in-ejb-30.html


왜 제네릭이 안되었는지 이제 알았다. 확실히...

먼저 제네릭이 안되었을때의 하이버네이트와 매핑한 bean을 살펴보면

 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 public Integer getUserSeq() {
     return userSeq;
 }

오류난 로그

2010-01-09 23:06 [DEBUG] opened session at timestamp: 12630460153
2010-01-09 23:06 [DEBUG] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
2010-01-09 23:06 [DEBUG] opening JDBC connection
2010-01-09 23:06 [DEBUG] select this_.userSeq as userSeq2_0_, this_.ANSWER as ANSWER2_0_, this_.BIRTH_DAY as BIRTH3_2_0_, this_.CREATE_DATE as CREATE4_2_0_, this_.DISABLE as DISABLE2_0_, this_.DOMAIN as DOMAIN2_0_, this_.E_MAIL as E7_2_0_, this_.EMAIL_DENY as EMAIL8_2_0_, this_.masterCodes as masterCo9_2_0_, this_.QUESTION as QUESTION2_0_, this_.RELATION_GROUP_SEQ as RELATION11_2_0_, this_.RELATION_SEQ as RELATION12_2_0_, this_.UPDATE_DATE as UPDATE13_2_0_, this_.USER_ID as USER14_2_0_, this_.USER_NAME as USER15_2_0_, this_.USER_NICK as USER16_2_0_, this_.USER_PW as USER17_2_0_, this_.USER_STATUS as USER18_2_0_ from MEMBER this_ where this_.USER_ID=? and this_.USER_PW=?
2010-01-09 23:06 [DEBUG] preparing statement
2010-01-09 23:06 [DEBUG] binding 'agnes0417' to parameter: 1
2010-01-09 23:06 [DEBUG] binding '~~~~~~~' to parameter: 2
2010-01-09 23:06 [DEBUG] about to open ResultSet (open ResultSets: 0, globally: 0)
2010-01-09 23:06 [DEBUG] processing result set
2010-01-09 23:06 [DEBUG] result set row: 0
2010-01-09 23:06 [DEBUG] returning null as column: userSeq2_0_
      -> primary key 가 null인게 있을리 없다..

2010-01-09 23:06 [DEBUG] result row: null
2010-01-09 23:06 [DEBUG] done processing result set (1 rows)
2010-01-09 23:06 [DEBUG] about to close ResultSet (open ResultSets: 1, globally: 1)
2010-01-09 23:06 [DEBUG] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
2010-01-09 23:06 [DEBUG] closing statement



@Column을 명시하지 않았기에 하이버네이트가 매핑된 이름 그대로 컬럼을 찾는다.
DB의 컬럼명은 USER_SEQ인데.. 만약 DB 컬럼명이 USERSEQ였다면 제네릭이 되었을테지만..

아래처럼 고쳐주었다..

 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 @Column(name="USER_SEQ")
 public Integer getUserSeq() {
      return userSeq;
 }

제대로 돌아간 로그 기록..

2010-01-09 23:01 [DEBUG] opened session at timestamp: 12630457058
2010-01-09 23:01 [DEBUG] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
2010-01-09 23:01 [DEBUG] opening JDBC connection
2010-01-09 23:01 [DEBUG] select this_.USER_SEQ as USER1_2_0_, this_.ANSWER as ANSWER2_0_, this_.BIRTH_DAY as BIRTH3_2_0_, this_.CREATE_DATE as CREATE4_2_0_, this_.DISABLE as DISABLE2_0_, this_.DOMAIN as DOMAIN2_0_, this_.E_MAIL as E7_2_0_, this_.EMAIL_DENY as EMAIL8_2_0_, this_.masterCodes as masterCo9_2_0_, this_.QUESTION as QUESTION2_0_, this_.RELATION_GROUP_SEQ as RELATION11_2_0_, this_.RELATION_SEQ as RELATION12_2_0_, this_.UPDATE_DATE as UPDATE13_2_0_, this_.USER_ID as USER14_2_0_, this_.USER_NAME as USER15_2_0_, this_.USER_NICK as USER16_2_0_, this_.USER_PW as USER17_2_0_, this_.USER_STATUS as USER18_2_0_ from MEMBER this_ where this_.USER_ID=? and this_.USER_PW=?
2010-01-09 23:01 [DEBUG] preparing statement
2010-01-09 23:01 [DEBUG] binding 'agnes0417' to parameter: 1
2010-01-09 23:01 [DEBUG] binding '~~~~~' to parameter: 2
2010-01-09 23:01 [DEBUG] about to open ResultSet (open ResultSets: 0, globally: 0)
2010-01-09 23:01 [DEBUG] processing result set
2010-01-09 23:01 [DEBUG] result set row: 0
2010-01-09 23:01 [DEBUG] returning '2' as column: USER1_2_0_
2010-01-09 23:01 [DEBUG] result row: EntityKey[com.jaeyeollee.model.join.Member#2]
2010-01-09 23:01 [DEBUG] Initializing object from ResultSet: [com.jaeyeollee.model.join.Member#2]
2010-01-09 23:01 [DEBUG] Hydrating entity: [com.jaeyeollee.model.join.Member#2]

2010-01-09 23:01 [DEBUG] returning null as column: DISABLE2_0_
2010-01-09 23:01 [DEBUG] returning '@naver.com' as column: DOMAIN2_0_
2010-01-09 23:01 [DEBUG] returning 'leepcs' as column: E7_2_0_
2010-01-09 23:01 [DEBUG] returning null as column: EMAIL8_2_0_
2010-01-09 23:01 [DEBUG] returning null as column: masterCo9_2_0_
2010-01-09 23:01 [DEBUG] returning '어머니 성함' as column: QUESTION2_0_
2010-01-09 23:01 [DEBUG] returning 'CG0000' as column: RELATION11_2_0_
2010-01-09 23:01 [DEBUG] returning 'CS0000' as column: RELATION12_2_0_
2010-01-09 23:01 [DEBUG] returning null as column: UPDATE13_2_0_
2010-01-09 23:01 [DEBUG] returning 'agnes0417' as column: USER14_2_0_
2010-01-09 23:01 [DEBUG] returning 'Hibernate' as column: USER16_2_0_
2010-01-09 23:01 [DEBUG] returning null as column: USER18_2_0_
2010-01-09 23:01 [DEBUG] done processing result set (1 rows)
2010-01-09 23:01 [DEBUG] about to close ResultSet (open ResultSets: 1, globally: 1)
2010-01-09 23:01 [DEBUG] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)

2010-01-09 23:01 [DEBUG] closing statement





그러니.. 제네릭이 된다.. 하하하;;;

아.. 볍신 인증했네...

난 Collection을 사용할때 항상 Generic 타입으로 객체를 생성하려한다.
이유야 generic을 사용하면 좀 간편해지니 (캐스팅을 할 필요도 없고..)

이유야 어쨋든 하이버 네이트에서도 제네릭을 붙여보았는데 ..


  1. Session session = getHibernateTemplate().getSessionFactory().openSession();
  2.  
  3. Criteria crit = session.createCriteria(Member.class);
  4. crit.add(Expression.eq("userId", member.getUserId()));
  5. crit.add(Expression.eq("userPw", member.getUserPw()));
  6.  
  7. List<Member> list = crit.list();

난 이게 될 줄 알았다. 정말 진짜...
심심풀이 만들어보고 있는데 이상하게 유저가 존재하는데도 session을 생성하려고하면 null을 뱉어내니 환장하는 수 밖에..

별 수단 다 써보다가 설마 싶어서 <Member>를 지우고 찍어보니.. 객체 주소가 찍히네...

그래서 도달한 결론은 7번 라인처럼 generic을 이용하여도 -
crit.list()를 하게 되면 return 되는 값들은 Object 형이므로 무조건 class Casting을 하여야 한다.

Membe rmember = (Member) list.get(0);

이렇게...  하면 틀린거고;;

http://yeory.tistory.com/46 여기를 참고하세요..

이글은 무식 인증 글임 ㅋ

+ Recent posts