- 浏览: 720844 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
yukang1:
太适合新手了 谢主隆恩
tomcat结合nginx使用小结 -
singformyself:
确实,楼主写的很好。必须赞一个。让我这个nginx新手如获至宝 ...
tomcat结合nginx使用小结 -
光太狼Leon:
这才是真正对新手有用的文章。
tomcat结合nginx使用小结 -
wangyudong:
由CXF实现的微服务需要有比较好的工具去测试RESTful A ...
JAVA webservice之CXF -
MCLoginandPwd:
如今,java技术框架太多了,给你分享一个好玩代码生成器,ht ...
论JAVA框架
从去年2月参加实习到现在已经差不多一年半没有碰三大框架啦,面对这三个庞然大物,看着真的有点心虚,要学通还真是要花不少的时间,但再困难也还是要去学习的,还是老老实实一步步走。
最近下了一本夏昕的《深入浅出hibernate》,不得不说这是一本好书,是国内难得的一本技术书。它不仅介绍了hibernate的用法,还讲解了基本的实现原理,一步步深入。
开始重新学习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。不知道是版本问题还是其他问题,我们明天再研究一下。如果有哪位兄弟知道为什么的,希望也不吝告诉我一下。
今天的研究就到这里,希望大家可以知道基本的实现自定义类型的方法。
发表评论
-
一个小小的hibernate学习之作
2011-06-21 21:20 1339经过前段时间hibernate的 ... -
hibernate中的Interceptor
2011-06-06 18:05 4440讲到Interceptor,相信熟 ... -
Hibernate中的Collection小谈
2011-06-05 15:48 2109记得我们在以前例子中一对多中用到的Set,还有印象么,如果没 ... -
hibernate之二级缓存小谈
2011-06-03 21:31 1571上次我们一起学习了一下hibernate的一级缓存及在运行过 ... -
hibernate状态和缓存小谈
2011-05-30 22:59 1549前几次我们讲了一些比 ... -
hibernate之HQL(3)
2011-05-29 15:38 3280我们在之前一起学习了Hibernate的HQL查询语法。但我 ... -
hibernate查询之HQL(2)
2011-05-28 16:19 2349我们上次一起学习HQL,知道了怎么使用HQL,现在我们继续来学 ... -
hibernate查询之HQL
2011-05-28 09:57 2170上次我们一起学习了用 ... -
hibernate查询之Criteria(2)
2011-05-27 00:05 1481我们前面看了一下Criteria的基本用法,下面我们来了解一 ... -
hibernate查询之Criteria
2011-05-26 22:44 2145前几次我们讲了hibernate的关联映射,映射完了我们就要 ... -
hibernate关联映射之多对多
2011-05-25 22:38 1653我们学习了hibernate的一对一和一对多,下面就剩下一个 ... -
hibernate关联映射之一对多
2011-05-25 21:56 1449看了一对一的实现之后,我们来看一下hibernate中一对多 ... -
hibernate关联映射之一对一(外键关联)
2011-05-24 22:59 1540上次我们说了hibernate关联映射中的一对一关联,我们是 ... -
hibernate关联映射之一对一
2011-05-24 00:41 1224作为一个ORM框架,hibern ... -
hibernate层次设计(2)
2011-05-22 21:00 1243昨天我们了解了怎么使 ... -
hibernate层次设计
2011-05-21 23:04 1810这次我们来说一下hibernate的层次设计,层次设计也就是 ... -
hibernate自定义类型(2)
2011-05-21 12:06 1577昨天讲了自定义类型中会出现异常,今天我们就来解决一下异常,文 ...
相关推荐
NULL 博文链接:https://gwoham-163-com.iteye.com/blog/1895101
struts+hibernate+自定义标签 做的分页模板
Hibernate——符合Java习惯的关系数据库持久化.pdf
hibernate和java类型转换,hibernate和java类型转换
hibernate自定义查询
Hibernate 4——Hello World
主要介绍了Hibernate Validation自定义注解校验的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
关于Hibernate的各种主键生成策略与配置详解
邮箱(hibernate+Servlet+自定义标签,内带hibernate配置,自定义标签分页)
本网上书店系统采用MVC设计模式,用Struts控制页面流程,Hibernate做对象持久化操作,分页功能是用自定义标签,在用户的登录过程中还用到了验证码功能,用过滤器过滤用户的权限!
简单的Hibernate实现Java通过多对多关联映射,进行学生课程管理。
主要介绍了Java的Hibernate框架中的自定义类型,Hibernate是Java的SSH三大web开发框架之一,需要的朋友可以参考下
hibernate映射枚举类型,hibernate如何映射枚举类型
解决Hibernate对于Date类型的数据返回结果中时分秒不对的问题
学习JPA——Hibernate_Annotation使用实例学习JPA——Hibernate_Annotation使用实例学习JPA——Hibernate_Annotation使用实例
Hibernate中数据类型,涵盖了所有数据库的字段类型与Java基本类型间的映射关系
NULL 博文链接:https://gwoham-163-com.iteye.com/blog/1885253
安卓Android源码——Hibernate4.zip