扼要剖析Java的Hibernate框架中的自界說類型。本站提示廣大學習愛好者:(扼要剖析Java的Hibernate框架中的自界說類型)文章只能為提供參考,不一定能成為您想要的結果。以下是扼要剖析Java的Hibernate框架中的自界說類型正文
比來看到hibernate的自界說類型,這個之前沒接觸過,在這裡記載一下,當是對本身常識的穩固,也讓沒有接觸過的同伙一路進修研討一番。
1)自界說類型,望文生義,固然就是因為外部的類型不知足需求,而本身來停止完成的類型。這類情形不多,但我們照樣有需要進修一下,技多不壓身嘛。也進修一下,他人在做框架的時刻是怎樣去斟酌的,怎樣去思慮擴大性的。
自界說類型有兩個辦法來完成,一種是完成UserType,別的一種完成CompositeUserType,別的能夠還有一些辦法,但我臨時沒用到,先不講了。
我臨時只用到UserType,我們就先看一下UserType接口的界說:
public interface UserType {
/**
* Return the SQL type codes for the columns mapped by this type. The
* codes are defined on <tt>java.sql.Types</tt>.
*/
public int[] sqlTypes();
/**
* The class returned by <tt>nullSafeGet()</tt>.
*/
public Class returnedClass();
/**
* Compare two instances of the class mapped by this type for persistence "equality".
* Equality of the persistent state.
*/
public boolean equals(Object x, Object y) throws HibernateException;
/**
* Get a hashcode for the instance, consistent with persistence "equality"
*/
public int hashCode(Object x) throws HibernateException;
/**
* Retrieve an instance of the mapped class from a JDBC resultset. Implementors
* should handle possibility of null values.
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException;
/**
* Write an instance of the mapped class to a prepared statement. Implementors
* should handle possibility of null values. A multi-column type should be written
* to parameters starting from <tt>index</tt>.
*/
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException;
/**
* Return a deep copy of the persistent state, stopping at entities and at
* collections. It is not necessary to copy immutable objects, or null
* values, in which case it is safe to simply return the argument.
*/
public Object deepCopy(Object value) throws HibernateException;
/**
* Are objects of this type mutable?
*
* @return boolean
*/
public boolean isMutable();
/**
* Transform the object into its cacheable representation. At the very least this
* method should perform a deep copy if the type is mutable. That may not be enough
* for some implementations, however; for example, associations must be cached as
* identifier values. (optional operation)
*
* @param value the object to be cached
* @return a cachable representation of the object
* @throws HibernateException
*/
public Serializable disassemble(Object value) throws HibernateException;
/**
* Reconstruct an object from the cacheable representation. At the very least this
* method should perform a deep copy if the type is mutable. (optional operation)
*/
public Object assemble(Serializable cached, Object owner) throws HibernateException;
/**
* During merge, replace the existing (target) value in the entity we are merging to
* with a new (original) value from the detached entity we are merging. For immutable
* objects, or null values, it is safe to simply return the first parameter. For
* mutable objects, it is safe to return a copy of the first parameter. For objects
* with component values, it might make sense to recursively replace component values.
*/
public Object replace(Object original, Object target, Object owner) throws HibernateException;
}
其實年夜家看英文普通情形下都能懂得,不再多做說明了,這裡我們最重要的就是完成nullSafeSet() 辦法,這個辦法重要用到把此類型的值保留到數據庫,這一次我們先學怎樣用,今後我們再漸漸研討外部是怎樣來完成的。
2)我進修時寫的例子是參照夏昕的例子,所以確定和網上的年夜部門都一樣,我們只是年夜概剖析一下:
上面是User類
package org.hibernate.tutorial.domain;
import java.io.Serializable;
import java.util.List;
public class User implements Serializable{
public Long id;
private String name;
private List emails;
省略Get/Set辦法
}
上去是自界說的EmailList類:
package org.hibernate.tutorial.domain;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class EmailList implements UserType {
private static final char SPLITTER = ';';
private static final int[] TYPES = new int[] {Types.VARCHAR};
private String assemble(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 value) {
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]);
}
return emailList;
}
public Object deepCopy(Object value) throws HibernateException {
List sourceList = (List)value;
List targetList = new ArrayList();
targetList.add(sourceList);
return targetList;
}
public Serializable disassemble(Object value) throws HibernateException {
return null;
}
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) return true;
System.out.println("X:"+x+"Y:"+y);
if (x != null && y != null) {
List xList = (List)x;
List yList = (List)y;
if(xList.size() != yList.size()) return false;
for (int i = 0; i < xList.size(); i++) {
String str1 = (String)xList.get(i);
String str2 = (String)yList.get(i);
if (!str1.equals(str2)) return false;
}
return true;
}
return false;
}
public boolean isMutable() {
return false;
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
String value = (String)Hibernate.STRING.nullSafeGet(rs, names[0]);
if (value != null) {
return parse(value);//把List經由過程;朋分
} else{
return null;
}
}
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
System.out.println("Set Method Executed!");
System.out.println("value:" + value);
if (value != null){
String str = assemble((List)value);//把字符串用;拼接
Hibernate.STRING.nullSafeSet(st, str, index);
} else {
Hibernate.STRING.nullSafeSet(st, value, index);
}
}
public Class returnedClass() {
return List.class;
}
public int[] sqlTypes() {
return TYPES;
}
//省略其他不須要修正的辦法
}
類中完成的辦法是須要修正的辦法,其他不須要修正臨時不消的辦法則沒有寫出來,但照樣須要完成的。
3)接上去就是User類的映照文件:
<class name="User" table="USER">
<id name="id" column="USER_ID" type="java.lang.Long">
<generator class="native" />
</id>
<property name="name" type="string" column="USER_NAME"/>
<property name="emails" type="org.hibernate.tutorial.domain.EmailList" column="emails"/>
</class>
信任年夜家都曉得怎樣停止修正,這裡也不停止講授了,重要是修正emails的type,修正為我們適才界說的EmailList類。
4)最初我們來寫一個測試類:
import java.util.HashMap;
import java.util.List;
import 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 extends TestCase{
private Session session = null;
protected void setUp() throws Exception {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
session = sessionFactory.openSession();
}
public void testInsert(){
Transaction tran = null;
try{
tran = session.beginTransaction();
User user = new User();
user.setName("shun");
List list = new ArrayList();
list.add("12312@sfsdf.com");
list.add("123@123.com");
user.setEmails(list);
session.save(user);
tran.commit();
} catch (Exception ex) {
ex.printStackTrace();
if (tran != null){
tran.rollback();
}
}
}
protected void tearDown() throws Exception {
session.close();
}
}
這裡能夠會湧現成績,當我們只保留一個email時,它會湧現異常,在數據庫外面是email字段是空的,而當我們如下面代碼一樣,有兩個時,其實不會湧現成績,數據庫中成果如圖:
而當我們只保留一個時,異常以下:
java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String
它產生在EmailList的equals辦法中的String str1 = (String)xList.get(i);這句代碼中,經檢討是在拔出數據傳到EmailList的nullSafeSet辦法時釀成了List的List,即
value:[[12312@sfsdf.com, 123@123.com]]如許的情勢,如許在比擬的時刻就會出成績,它永久都只要一個值,而在比擬的時刻倒是分歧的,
if(xList.size() != yList.size()) return false;
所以在強迫轉換時會出成績。
而經由檢討,equals辦法裡:
X:[[12312@sfsdf.com, 123@123.com]]Y:[12312@sfsdf.com, 123@123.com]
如許的成果倒是很奇異的。網上並沒有講到為何會湧現這類情形。這裡提出一下:我用的hibernate版本是Hibernate 3.3.2.GA。不曉得是版本成績照樣其他成績,我們今天再研討一下。假如有哪位兄弟曉得為何的,願望也不惜告知我一下。