나는 최근에 최대 절전 모드의 맞춤형 유형을 보았다. 나는 전에 노출 된 적이 없다. 나는 여기에 그것을 내 지식의 통합으로 기록하고 함께 배우고 공부하는 데 노출 된 적이없는 친구들을 데려 갈 것입니다.
1) 이름에서 알 수 있듯이 사용자 정의 유형은 내부 유형이 요구를 충족시키지 않기 때문에 자체적으로 구현되는 유형입니다. 그러한 상황은 많지 않지만 여전히 배워야합니다. 더 많은 기술이 있으면 몸을 억제하지 않을 것입니다. 또한 다른 사람들이 프레임 워크를 만들 때 확장성에 대해 생각하는 방법을 고려하는 방법을 배우십시오.
사용자 정의 유형을 구현하는 두 가지 방법이 있습니다. 하나는 userType를 구현하는 것이고 다른 하나는 compositeUserType를 구현하는 것이며 몇 가지 방법이있을 수 있지만 당분간 사용하지 않았으므로 지금은 이야기하지 않을 것입니다.
당분간 사용자 유형을 사용하고 있습니다. 먼저 사용자 유형 인터페이스의 정의를 살펴 보겠습니다.
공개 인터페이스 userType { /***이 유형에 매핑 된 열의 SQL 유형 코드를 반환합니다. * 코드는 <tt> java.sql.types </tt>에 정의됩니다. */ public int [] sqltypes (); /*** 클래스는 <tt> nullsafeget () </tt>에 의해 반환되었습니다. */ public class returnedClass (); /*** 지속성 "평등"을 위해이 유형에 의해 매핑 된 클래스의 두 인스턴스를 비교하십시오. * 지속적인 상태의 평등. */ public boolean Equals (Object X, Object Y)는 최대 절전 모드를 던졌습니다. / ** * 지속성 "평등" */ public int hashcode (Object X)와 일치하는 인스턴스에 대한 해시 코드를 얻습니다. /*** JDBC 결과 세트에서 매핑 클래스의 인스턴스를 검색합니다. 구현 자 *는 널 값의 가능성을 처리해야합니다. */ public Object nullsafeget (resultet rs, string [] 이름, 개체 소유자)은 hibernateException, sqlexception; /*** 맵핑 클래스의 인스턴스를 준비된 문에 작성하십시오. 구현 자 *는 널 값의 가능성을 처리해야합니다. <tt> index </tt>에서 시작하는 다중 열 유형 *에 매개 변수를 작성해야합니다. */ public void nullsafeset (preadstatement st, 객체 값, int index)은 최대 절전 모드, sqlexception; /** * 지속적인 상태의 깊은 사본을 반환하고 엔티티와 컬렉션에서 멈 춥니 다. 불변의 물체 또는 null * 값을 복사 할 필요는 없으며,이 경우 단순히 인수를 반환하는 것이 안전합니다. */ public Object DeepCopy (객체 값)는 최대 절전 모드를 던졌습니다. /***이 유형의 객체는 변동성이 있습니까? * * @return boolean */ public boolean ismutable (); /*** 객체를 캐시 가능한 표현으로 변환합니다. 최소한이 * 메소드는 유형이 변하는 경우 딥 카피를 수행해야합니다. 그러나 일부 구현에는 충분하지 않을 수 있습니다. 예를 들어, 협회는 * 식별자 값으로 캐시해야합니다. (선택적 작동) * * @param 값 캐시 할 객체 * @return 객체의 캐시 가능한 표현 * @throws hibernateexception */ public serializable disassemble (객체 값)는 HibernateException을 던졌습니다. /*** 캐시 가능한 표현에서 물체를 재구성합니다. 최소한이 * 메소드는 유형이 변하는 경우 딥 카피를 수행해야합니다. (선택적 조작) */ 공개 객체 어셈블 (시리얼 화 가능한 캐시, 개체 소유자)은 최대 절전 모드를 던졌습니다. /** * 병합 중에 합병되는 엔티티의 기존 (대상) 값을 병합하는 분리 된 엔티티의 새로운 (원본) 값으로 바꾸십시오. 불변의 * 객체 또는 NULL 값의 경우 단순히 첫 번째 매개 변수를 반환하는 것이 안전합니다. * Mutable Objects의 경우 첫 번째 매개 변수의 사본을 반환하는 것이 안전합니다. 구성 요소 값이있는 개체 *의 경우 구성 요소 값을 재귀 적으로 교체하는 것이 합리적 일 수 있습니다. */ public Object Replare (Object Original, Object Target, Object Owner)는 HibernateException을 던집니다. } 실제로, 당신은 일반적으로 영어로 그것을 이해할 수 있으므로 더 이상 설명하지 않을 것입니다. 여기서는 NullSafeset () 메소드를 구현하는 것이 가장 중요합니다. 이 방법은 주로이 유형의 값을 데이터베이스에 저장합니다. 이번에는 먼저 사용하는 방법을 배우고 내부적으로 구현되는 방식을 천천히 연구 할 것입니다.
2) 내가 공부할 때 쓴 사례는 Xia Xin의 사례를 언급 한 것이므로 대부분의 온라인과 동일합니다. 대략 분석하자 :
아래는 사용자 클래스입니다
패키지 org.hibernate.tutorial.domain; java.io.serializable import; Java.util.list 가져 오기; 공개 클래스 사용자는 직렬화 가능 {public long id; 개인 문자열 이름; 개인 목록 이메일; GET/SET Method를 생략}} 다음은 사용자 정의 emaillist 클래스입니다.
패키지 org.hibernate.tutorial.domain; java.io.serializable import; Java.sql.preparedStatement import; java.sql.resultset import; java.sql.sqlexception 가져 오기; java.sql.sql.types import; java.util.arraylist 가져 오기; Java.util.list 가져 오기; import org.hibernate.hibernate; import org.hibernate.hibernateException; import org.hibernate.usertype.usertype; 공개 클래스 emaillist는 usertype {private static final char splitter = ';'; 개인 정적 최종 int [] type = new int [] {type.varchar}; 개인 문자열 조립 (list emaillist) {StringBuilder strbuf = new StringBuilder (); for (int i = 0; i <emaillist.size () -1; i ++) {strbuf.append (emaillist.get (i)). Append (splitter); } strbuf.append (emaillist.get (emaillist.size () -1)); return strbuf.tostring (); } private list parse (문자열 값) {string [] strs = org.hibernate.util.stringhelper.split (value, string.valueof (splitter)); list emaillist = new arraylist (); for (int i = 0; i <strs.length; i ++) {emaillist.add (strs [i]); } 반환 emaillist; } public Object DeepCopy (객체 값) hibernateException {list sourcelist = (list) 값; 목록 targetList = new ArrayList (); TargetList.Add (Sourcelist); 대상 목록을 반환합니다. } 공개 직렬화 가능한 분해 (객체 값) hibernateException {return null; } public boolean Equals (Object X, Object Y)는 최대 절전 모드를 던졌습니다. {if (x == y) true; System.out.println ( "x :"+x+"y :"+y); if (x! = null && y! = null) {list xlist = (list) x; List YLIST = (목록) y; if (xlist.size ()! = ylist.size ()) false를 반환합니다. for (int i = 0; i <xlist.size (); i ++) {String str1 = (String) xlist.get (i); 문자열 str2 = (string) ylist.get (i); if (! str1.equals (str2)) false를 반환합니다. } true를 반환합니다. } false를 반환합니다. } public boolean ismutable () {return false; } public Object NullSafeget (restet rs, string [] 이름, 개체 소유자)은 HibernateException, sqlexception {string value = (String) hibernate.string.nullsafeget (rs, names [0]); if (value! = null) {return parse (value); // 목록을 붙여 넣습니다. split} else {return null; }} public void nullsafeset (preadStatement st, 객체 값, int index)은 HibernateException, sqlexception {System.out.println ( "set set method!"); System.out.println ( "value :" + value); if (value! = null) {string str = assemble ((list) value); // 문자열 사용; Splice Hibernate.string.nullsafeset (st, str, index); } else {hibernate.string.nullsafeset (st, value, index); }} public class returnedClass () {return list.class; } public int [] sqltypes () {반환 유형; } // 수정이 필요하지 않은 다른 방법을 생략}} 클래스에서 구현 된 방법은 수정 해야하는 방법과 당분간 수정할 필요가없는 기타 방법이 작성되지 않았지만 여전히 구현해야합니다.
3) 다음은 사용자 클래스의 매핑 파일입니다.
<class name = "user"table = "user"> <id name = "id"열 = "user_id"type = "java.lang.long"> <generator/</id> <property name = "name"type = "string"열 = "user_name"/> <property name = "emails"org.hibernate.tutorial.mailist ""emails ""emails ""emails "
나는 모든 사람들이 그것을 수정하는 방법을 알고 있다고 생각하며 여기서 설명하지 않을 것입니다. 주로 이메일 유형을 변경하고 방금 정의한 Emaillist 클래스로 변경합니다.
4) 마지막으로 테스트 클래스를 작성하겠습니다.
java.util.hashmap import; Java.util.list 가져 오기; java.util.map import; java.util.arraylist 가져 오기; import junit.framework.testcase; import org.hibernate.entityMode; import org.hibernate.session; import org.hibernate.sessionfactory; import org.hibernate.Transaction; import org.hibernate.cfg.configuration; import org.hibernate.tutorial.domain.user; Public Class HiberNateTest는 테스트 케이스를 확장합니다. {개인 세션 세션 = null; Protected void setup ()은 예외를 던져 {configuration cfg = new configuration (). configure (); SessionFactory SessionFactory = CFG.BuildSessionFactory (); 세션 = sessionfactory.opensession (); } public void testinsert () {transaction tran = null; try {tran = session.begintransaction (); 사용자 user = 새 사용자 (); user.setName ( "shun"); 목록 목록 = new ArrayList (); list.add ( "[email protected]"); list.add ( "[email protected]"); user.seteMails (list); 세션 .SAVE (사용자); tran.commit (); } catch (예외) {ex.printstacktrace (); if (tran! = null) {tran.rollback (); }} protected void intewdown ()은 예외 {session.close (); }} 여기에 문제가있을 수 있습니다. 이메일 하나만 저장하면 예외가 있습니다. 데이터베이스의 이메일 필드는 비어 있습니다. 위 코드와 같은 두 가지 코드가 있으면 아무런 문제가 없습니다. 데이터베이스의 결과는 그림과 같습니다.
그리고 하나만 저장하면 예외는 다음과 같습니다.
java.lang.classcastException : java.util.arraylist는 java.lang.string으로 캐스트 할 수 없습니다
그것은 emaillist, string str1 = (string) xlist.get (i)의 평등 방법에서 발생합니다. 이 코드에서 확인 후 데이터를 삽입하여 Emaillist의 NullSafeset 메소드에 전달할 때 목록 목록이됩니다.
가치 : [[[email protected], [email protected]]]]이 양식은 비교할 때 문제를 일으킬 것입니다. 항상 값이 하나 뿐이지 만 비교할 때는 다릅니다.
if (xlist.size ()! = ylist.size ()) false를 반환합니다.
따라서 캐스팅 할 때 문제가있을 것입니다.
검사 후 동등한 방법 :
X : [[[email protected], [email protected]]] y : [[email protected], [email protected]]
이 결과는 매우 이상합니다. 인터넷은 왜이 상황이 발생했는지에 대해 이야기하지 않았습니다. 여기에 제안하겠습니다 : 내가 사용하는 최대 절전 모드 버전은 최대 절전 모드 3.3.2.ga입니다. 버전 문제인지 다른 문제인지 모르겠습니다. 내일 공부합시다. 왜 그런지 아는 사람이라면 말해 줄 수 있기를 바랍니다.