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

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

阅读更多

本篇介绍hibernate的自定义数据类型的用法

 

      有些时候,出于设计上的统一性考虑,需要针对数据结构可能重复出现的数据模式,引入一些自定义数据类型。也就是说,目的是对某些数据处理方式封装起来,让系统业务逻辑更清晰。

 

UserType

       这是一个Hibernate的接口,阁下可到官方Doc阅览个梗概:              http://docs.jboss.org/hibernate/orm/4.1/javadocs/

 

       此处举一例以说明之,假设有一member实体,表中有一个email字段为varchar类型,但实际上member可以拥有多个email地址,对应的POJO中email为一个List。

有一计谋为:在表中的email字段存储形式为 “xxx@xxx.com;ooo@ooo.com;...”即以“;”为分隔符将多个email拼接起来成为一个字符串。从表中读取时再将其处理成List,

逐个存放email。此时,我们可以通过Hibernate中的自定义类型为email字段做处理,将上述的繁琐逻辑封装起来,请看以下项目:

 

采用Maven搭建,MySQL做DB,只需专注跟TMember相关的材料即可:

项目结构:


 

1.SQL

create table t_member (
  id int(11) not null primary key,
  name varchar(80) not null,
  email varchar(120)
);

 

2.pom.xml(maven 项目,通过其可以非常方便引入所需jar包)

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>learnHibernate</groupId>
	<artifactId>learnHibernate</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>learnHibernate</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.8.2</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>4.1.4.Final</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-ehcache</artifactId>
			<version>4.1.4.Final</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-c3p0</artifactId>
			<version>4.1.4.Final</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.15</version>
		</dependency>
		
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.6.1</version>
		</dependency>
		
	</dependencies>
</project>

 

3.hibernate.cfg.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

	<session-factory>
		<property name="hibernate.connection.driver_class">
			com.mysql.jdbc.Driver
        </property>
		<property name="hibernate.dialect">
			org.hibernate.dialect.MySQLDialect
        </property>
		<property name="hibernate.connection.url">
			jdbc:mysql://localhost:3306/hibernate
        </property>
		<property name="hibernate.connection.username">
			root
       </property>
		<property name="hibernate.connection.password">
			root
        </property>
		<property name="hibernate.show_sql">
			true
		</property>
		<property name="hibernate.format_sql">
			true
		</property>

		<!-- 配置C3P0 -->
		<property name="hibernate.connection.provider_class">
			org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider
        </property>
		<property name="hibernate.c3p0.max_size">10</property>
		<property name="hibernate.c3p0.min_size">1</property>
		<property name="hibernate.c3p0.max_statements">3</property>
		<property name="hibernate.c3p0.timeout">30</property>
		<property name="hibernate.c3p0.acquire_increment">1</property>
		<property name="hibernate.c3p0.idle_test_periodt">10</property>

		<!-- 配置二级缓存 -->
		<property name="hibernate.cache.use_second_level_cache">true</property>
		<property name="hibernate.cache.use_query_cache">true</property>

		<!-- Hibernate4 这里和Hibernate3不一样 要特别注意!!!-->

		<property name="hibernate.cache.region.factory_class">
			org.hibernate.cache.EhCacheRegionFactory
		</property>
		<!-- Hibernate3 -->
		<!--
			<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
		-->
		
		<!-- 实体映射文件 -->
		<mapping resource="learnHibernate/bean/TUser.hbm.xml" />
		<mapping resource="learnHibernate/bean/TMember.hbm.xml" />

	</session-factory>

</hibernate-configuration>

 

4.HibernateLocalUtil.java

package learnHibernate.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

public final class HibernateLocalUtil {

	private static SessionFactory sessionFactory;	
	
	private HibernateLocalUtil() {
		
	}
	
	static {
		try {
			Configuration configuration = new Configuration().configure("hibernate\\hibernate.cfg.xml");
			ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
						.applySettings(configuration.getProperties()).buildServiceRegistry();
			sessionFactory = configuration.buildSessionFactory(serviceRegistry);
			
		}catch (Throwable e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	public static SessionFactory getSessionFactory () {
		return sessionFactory;
	}
}

 

5.TMember.java

package learnHibernate.bean;

import java.io.Serializable;
import java.util.List;

public class TMember implements Serializable{
	private static final long serialVersionUID = -2487367694260008988L;
	
	private int id;
	private String name;
	private List email;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public List getEmail() {
		return email;
	}
	public void setEmail(List email) {
		this.email = email;
	}
}

 

6.TMember.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  
<hibernate-mapping package="learnHibernate.bean">
	<class name="TMember" table="t_member">
		<id name="id" column="id" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		
		<property name="name" column="name" type="java.lang.String"/>
		<property name="email" column="email" type="learnHibernate.bean.EmailList" />
	</class>
	
</hibernate-mapping>

 

7.EmailList.java(本例关键核心所在)

package learnHibernate.bean;

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.engine.spi.SessionImplementor;
import org.hibernate.type.StringType;
import org.hibernate.type.Type;
import org.hibernate.usertype.UserType;

public class EmailList implements UserType {

	private static final String seperator = ";";
	
	private static final int[] TYPES = new int[] {Types.VARCHAR};
	
	/**
	 * 重新构建一个处于可缓存状态的对象
	 */
	@Override
	public Object assemble(Serializable arg0, Object arg1)
			throws HibernateException {
		// TODO Auto-generated method stub
		return null;
	}
	
	/**
	 * 提供自定义类型的完全复制方法
	 * 本方法将用作构造返回对象
	 * 当nullSafeGet方法调用后,我们获得了自定义数据对象。在向用户返回
	 * 自定义数据之前,deepCopy方法将被调用,它将根据自定义数据对象构造
	 * 一个完全的copy,并将copy返回给用户使用。
	 * 此时,我们就得到了自定义数据对象的两个版本,第一个是从数据库读出的原始
	 * 版本,其二是我们通过deepCopy构造的复制版本,原始版本将有hibernate负责维护,
	 * 复制版本将由用户使用,原始版本用作稍后的脏数据检查依据;hibernate将在脏数据检查
	 * 过程中将两个版本的数据进行比对(通过调用equals方法),如果数据发生了变化(equals返回false),
	 * 则执行对应的持久化操作
	 */
	@Override
	public Object deepCopy(Object value) throws HibernateException {
		if(value != null) {
			List sourceList = (List)value;
			List trgList = new ArrayList();
			trgList.addAll(sourceList);
			return trgList;
		}
		return null;
	}
	
	/**
	 * 将对象转化为可缓存状态 
	 */
	@Override
	public Serializable disassemble(Object arg0) throws HibernateException {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * 自定义数据类型额对比方法
	 * 此方法将用作脏数据检查,参数代表两个副本,
	 * 若equals返回false,则hibernate将认为数据发生变化,并将变化更新到数据库
	 */
	@Override
	public boolean equals(Object x, Object y) throws HibernateException {
		if(x == y) return true;
		
		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 xStr = (String)xList.get(i);
				String yStr = (String)yList.get(i);
				if( !xStr.equals(yStr) ) return false;
			}
			
			return true;
		}
		return false;
	}

	@Override
	public int hashCode(Object arg0) throws HibernateException {
		return 0;
	}

	/**
	 * 本类型实例是否可变
	 */
	@Override
	public boolean isMutable() {
		return false;
	}
	
	/**
	 * 从JDBC ResultSet读取数据,将其转换为自定义类型后返回
	 * (此方法要求对可能出现的null值进行处理)
	 * names中包含了当前自定义类型的映射字段名称。
	 * 此处从resultSet中取出email字段,并将其解析为List类型后返回
	 */
	@Override
	public Object nullSafeGet(ResultSet rs, String[] names,
			SessionImplementor session, Object owner) throws HibernateException,
			SQLException {
		String value = StringType.INSTANCE.nullSafeGet(rs, names[0], session);
		
		if(value != null) {
			return _parseToList(value);
		}else {
			return null;
		}
	}

	/**
	 * 本方法将在hibernate进行数据保存时被调用
	 * 可以通过preparedStatement将自定义数据写入对应的库表字段
	 * 此处将List型的email信息组装成字符串之后保存到email字段
	 */
	@Override
	public void nullSafeSet(PreparedStatement st, Object value, int index,
			SessionImplementor session) throws HibernateException, SQLException {
		System.out.println("Set method executed");
		
		if(value != null) {
			String str = _parseToStr((List)value);
			StringType.INSTANCE.nullSafeSet(st, str, index, session);
		}else {
			StringType.INSTANCE.nullSafeSet(st, value, index, session);
		}
	}

	/**
	 * 在下不明白此方法作用,若有知者能在留言指点一二,不胜感激
	 */
	@Override
	public Object replace(Object arg0, Object arg1, Object arg2)
			throws HibernateException {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * UserType.nullSafeGet()所返回的自定义数据类型
	 */
	@Override
	public Class returnedClass() {
		return List.class;
	}

	/**
	 * 返回UserType所映射字段的SQL类型(java.sql.Types)
	 * 返回类型为int[],其中包含了映射各字段的SQL类型代码(UserType可以映射到一个或者多个字段)
	 */
	@Override
	public int[] sqlTypes() {
		return TYPES;
	}
	
	private List _parseToList(String value) {
		String[] strArr = value.split(seperator);
		List emailList = new ArrayList();
		
		for(int i=0; i<strArr.length; i++) {
			emailList.add(strArr[i]);
		}
		return emailList;
	}
	
	private String _parseToStr(List emailList) {
		StringBuffer strBuf = new StringBuffer();
		for(int i=0; i<emailList.size()-1; i++) {
			strBuf.append(emailList.get(0)).append(seperator);
		}
		
		strBuf.append(emailList.get(emailList.size()-1));
		
		return strBuf.toString();
	}

}

 

8. TestCase2.java(测试用例Junit4.8.2,若阁下使用Eclipse并有Junit插件,右键Junit test即可)

package learnHibernate;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Test;

import learnHibernate.bean.TMember;
import learnHibernate.util.HibernateLocalUtil;

public class TestCase2 {

//	@Test
	public void saveTMember() {
		TMember t = new TMember();
		List emailList = new ArrayList();
		emailList.add("gwoham@163.com");
		emailList.add("gwoham@gmail.com");
		emailList.add("2210635870@qq.com");
		t.setName("Oham");
		//t.setEmail(emailList);
		
		SessionFactory sessionFactory = HibernateLocalUtil.getSessionFactory();
		Session session = sessionFactory.openSession();
		
		Transaction tx = session.beginTransaction();
		session.save(t);
		tx.commit();
		session.close();
	}
	
	@Test
	public void selectAllTMember() {
		SessionFactory sessionFactory = HibernateLocalUtil.getSessionFactory();
		Session session = sessionFactory.openSession();
		
		Criteria criteria = session.createCriteria(TMember.class);
		
		List members = criteria.list();
		
		for(Object t : members) {
			TMember m = (TMember)t;
			List emailList = m.getEmail();
			
			if(emailList != null) {
				System.out.println(emailList.toString());
			}else {
				System.out.println("no email");
			}
		}
		session.close();
	}
}

 

 请君动手搞一搞,为求得一个体会

 

 

  • 大小: 11.8 KB
分享到:
评论

相关推荐

    Hibernate实战

    《Hibernate实战》这本书深入浅出地探讨了Java领域中广泛使用的对象关系映射框架——Hibernate。Hibernate是一个开源的ORM框架,它为Java开发者提供了一种高效、便捷的方式来管理数据库操作,消除了Java对象与SQL...

    Hibernate 手册中文版chm格式

    13. 扩展和自定义:讨论如何扩展Hibernate,如实现自定义类型、事件监听器和拦截器等。 通过学习这个手册,开发者不仅可以掌握Hibernate的基本用法,还能了解到高级特性和最佳实践,从而在实际项目中更加高效地利用...

    Hibernate5实例程序

    通过ORM,Hibernate将Java对象与数据库中的记录进行映射,使得开发者可以使用面向对象的方式来处理数据。 2. **环境配置** 在开始使用Hibernate5之前,需要安装JDK、配置Java环境,然后引入Hibernate5的jar包或者...

    Hibernate数据访问技术大全

    接着,书中深入探讨了Hibernate的查询语言——HQL(Hibernate Query Language)和Criteria API,它们提供了更面向对象的方式来查询数据,避免了直接使用SQL的复杂性。HQL类似于SQL,但操作的是对象而非表格,而...

    Hibernate 转译中文版

    10. **类型转换**:Hibernate支持自定义类型转换,允许开发者将Java类型与数据库类型进行映射,例如日期时间格式的转换。 总的来说,《Hibernate 转译中文版》涵盖了Hibernate框架的各个方面,从基本概念到高级特性...

    hibernate-3.2.6下载

    6. 可扩展性:允许开发者通过插件机制自定义行为,如实体监听器、类型转换器等。 7. 性能优化:包括更有效的缓存策略、延迟加载优化等,提升了整体性能。 在实际开发中,理解并熟练使用Hibernate 3.2.6的关键在于...

    Hibernate tool 源代码

    源代码揭示了它们之间的接口调用关系,如如何通过Hibernate API获取数据库元数据,以及如何使用Hibernate的Annotation Processor在编译时进行ORM验证。这对于我们深入理解Hibernate的工作原理和优化ORM配置提供了...

    hibernate全套学习课件ppt

    12. **事件监听器**:Hibernate提供了一些预定义的事件,如保存、更新、删除等,可以通过实现相应的监听器接口,自定义数据操作前后的行为。 13. **实体生命周期**:Hibernate定义了几个关键的生命周期状态,如瞬...

    hibernate validator jsr303

    此外,Hibernate Validator 还提供了一个强大的表达式语言——EL (Expression Language),允许开发者在注解中使用复杂的条件逻辑。 **主要组件** 1. **hibernate-validator-5.4.2.Final.jar**:这是Hibernate ...

    精通Hibernate源代码jar包3

    Hibernate提供了一种强大的查询语言——Hibernate Query Language (HQL),它类似SQL但面向对象。此外,还有Criteria API,提供了更面向对象的方式来构建查询。在源代码中,可以深入了解这些查询机制的实现细节。 4...

    Hibernate中文开发文档

    11. **自定义类型和事件监听**: Hibernate允许开发者定义自定义类型,以便处理特殊的数据类型。同时,还可以注册事件监听器来监听对象的生命周期事件。文档会介绍如何实现这些功能。 12. **性能优化**: 最后,文档...

    Hibernate源代码项目

    例如,通过实现` UserType`接口可以扩展Hibernate对特定数据类型的处理能力。 8. **性能优化**: 深入源代码,我们可以了解Hibernate的延迟加载(Lazy Loading)、批处理(Batch Processing)等性能优化策略,这些...

    轻量级Java EE企业应用开发实战———Struts 2+Spring+Hibernate整合开发 课件

    通过学习《轻量级Java EE企业应用开发实战———Struts 2+Spring+Hibernate整合开发》这本书籍和配套的课件,开发者可以深入理解 SSM 框架的原理和实践,掌握企业级应用开发的关键技能。课程中可能涵盖了如何搭建...

    hibernate v3.12中文参考手册

    8. **类型转换(Type Mapping)**:Hibernate允许自定义类型转换,以便处理特殊的数据类型。手册会介绍标准类型和自定义类型的使用。 9. **拦截器(Interceptors)**:拦截器允许在特定的生命周期事件中插入自定义...

    hibernate课程源码.

    5. **008_Hibernate_ExtendsORM**: 这可能涉及到Hibernate的扩展和对象关系映射的高级主题,如自定义类型、事件监听器或者二级缓存等,这些特性增强了Hibernate的功能和性能。 6. **011_Hibernate_DML**: DML(Data...

    hibernate-distribution-3.3.2.GA-dist

    这个压缩包中不仅有运行时所需的jar文件,还包含了详细的API文档——javadoc,这对于开发者理解和使用Hibernate提供了极大的便利。 Hibernate的核心功能在于对象关系映射,它允许开发者以面向对象的方式来处理...

    夏昕《Hibernate开发指南》V3.0.4

    4. **缓存机制**:为了提高应用程序性能,Hibernate 提供了两级缓存机制——一级缓存是会话级别的缓存,由 Hibernate 自动管理;二级缓存则可以自定义实现策略,以满足不同的应用场景需求。 #### 三、Hibernate的...

Global site tag (gtag.js) - Google Analytics