`
cxshun
  • 浏览: 724574 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

重拾hibernate——自定义类型

阅读更多

从去年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。不知道是版本问题还是其他问题,我们明天再研究一下。如果有哪位兄弟知道为什么的,希望也不吝告诉我一下。

今天的研究就到这里,希望大家可以知道基本的实现自定义类型的方法。

  • 大小: 1.6 KB
0
0
分享到:
评论

相关推荐

    Hibernate使用——自定义数据类型

    本篇文章将深入探讨如何在Hibernate中实现自定义数据类型。 首先,我们需要理解Hibernate是如何处理数据类型的。默认情况下,Hibernate使用Java的标准数据类型来映射数据库中的列。例如,Integer对应INT,String...

    简要分析Java的Hibernate框架中的自定义类型

    在Java的Hibernate框架中,自定义类型是一种非常实用的功能,它允许开发者根据特定业务需求扩展Hibernate内置的数据类型。当我们发现Hibernate默认的数据类型无法满足我们存储数据的特殊要求时,例如需要处理复杂...

    hibernate + 自定义标签分页

    本例中,我们探讨的是如何结合Struts、Hibernate和自定义标签实现分页功能,这是一种常见的优化用户界面体验的技术,特别是对于数据量大的查询结果。 1. **分页原理** 分页的基本思想是将大量数据分成多个小部分,...

    hibernate自定义查询

    在Hibernate中,自定义查询是扩展其功能的重要方式,能够帮助我们实现更复杂的数据库交互需求。本文将深入探讨Hibernate自定义查询的相关知识点。 一、Hibernate HQL查询 Hibernate Query Language (HQL) 是...

    Hibernate Validation自定义注解校验的实现

    Hibernate Validation自定义注解校验的实现 Hibernate Validation自定义注解校验的实现是指在Hibernate Validation框架中,使用自定义的注解来实现特定的校验逻辑。在本文中,我们将通过示例代码,详细地介绍如何...

    Hibernate——符合Java习惯的关系数据库持久化

    Hibernate是一款深受Java开发者喜爱的开源对象关系映射(ORM)框架,它为Java应用程序提供了一种方便、高效的方式来操作关系型数据库。通过使用Hibernate,开发人员可以避免直接编写大量的SQL语句,而是使用面向对象...

    Struts+Hibernate+自定义标签的网上书店

    本网上书店系统是一个基于MVC(Model-View-Controller)设计模式的Web应用程序,它整合了Java的两大核心框架——Struts和Hibernate,以及自定义标签技术,旨在提供一个高效、安全的图书浏览与购买平台。 **1. ...

    用Hibernate实现领域对象的自定义字段

    本文将深入探讨如何使用Hibernate实现领域对象的自定义字段,这涉及到对Hibernate核心概念的理解以及自定义类型的应用。 首先,我们需要了解Hibernate的核心概念。Hibernate主要通过配置文件(hibernate.cfg.xml)...

    JAVA数据类型与Hibernate的类型映射

    而在Java持久化框架Hibernate中,这些数据类型需要与数据库中的字段类型进行映射,以便正确地存储和检索数据。这篇博客主要探讨了Java数据类型如何与Hibernate的类型映射进行对应。 首先,Java的基本数据类型在...

    解决Hibernate对于Date类型的数据返回结果中时分秒不对的问题

    - **自定义Type**:创建自定义的Hibernate类型,覆盖默认的日期时间处理方式,以满足特定需求。 以上就是关于"解决Hibernate对于Date类型的数据返回结果中时分秒不对的问题"的详细分析和解决方案。在实际开发中,...

    Hibernate使用——入门

    **Hibernate使用——入门** Hibernate 是一个强大的开源对象关系映射(ORM)框架,它简化了Java应用程序与数据库之间的交互。这篇博文将引导你入门Hibernate,理解其基本概念和使用方法。 **1. Hibernate概述** ...

    Hibernate 4——Hello World

    在本文中,我们将深入探讨如何使用Hibernate 4框架进行初步的“Hello World”实践。Hibernate是一个流行的开源对象关系映射(ORM)框架,它简化了Java应用程序与数据库之间的交互。通过将Java对象与数据库表之间的...

    Hibernate各种主键生成策略与配置详解

    关于Hibernate的各种主键生成策略与配置详解

    精通hibernate3.0(第三版).rar

    6. Criteria API与Querydsl:讨论Criteria API的高级用法,以及Querydsl这样的类型安全查询库如何与Hibernate集成,提升查询代码的可读性和可维护性。 7. 引入CGLIB和JPA:阐述Hibernate如何利用CGLIB实现动态代理...

    hibernate映射Oracle中LONG类型

    使用自定义类型映射 Oracle 中的 LONG 类型字段是解决 Hibernate 框架中 LONG 类型字段读写问题的一种有效方法。通过实现 UserType 接口,我们可以定制 LONG 类型字段的读写操作,并提高 Hibernate 框架的灵活性和可...

    邮箱(hibernate+Servlet+自定义标签,内带hibernate配置,自定义标签分页)

    标题和描述中提到的"邮箱(hibernate+Servlet+自定义标签,内带hibernate配置,自定义标签分页)"是一个基于Java技术栈的Web应用项目,它利用Hibernate作为持久层框架,Servlet作为控制层,以及自定义标签来实现前端展示...

    hibernate 调用oracle函数

    文档可能涵盖了更复杂的场景,如处理多参数函数、处理复杂返回类型、以及在事务管理中调用函数等。 总的来说,Hibernate调用Oracle函数涉及到了数据库设计、ORM框架的使用、原生SQL查询和结果映射等多个方面,熟练...

    hibernate和java类型转换

    hibernate和java类型转换,hibernate和java类型转换

    Java数据类型,Hibernate数据类型,标准sql数据类型之间的对应表

    此外,Hibernate还支持自定义数据类型的映射,允许开发者根据需求扩展和定制。 在实际开发中,理解这些映射关系至关重要,因为它直接影响到数据的存储和查询效率,以及数据的一致性和完整性。例如,如果错误地将...

Global site tag (gtag.js) - Google Analytics