`
oham_一1一
  • 浏览: 49887 次
  • 性别: 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
分享到:
评论

相关推荐

    Java Web程序设计教程

    4.2.3使用jdbc读取数据 69 4.3项目实战——存储图书信息 73 本章小结 78 课后练习 79 第5章struts2框架基础 80 5.1mvc框架 80 5.1.1model1与model2 80 5.1.2mvc设计模式 81 5.1.3struts2框架的mvc架构 82 ...

    低清版 大型门户网站是这样炼成的.pdf

    4.3.1 hibernate的基本映射数据类型 212 4.3.2 hibernate的主键映射 218 4.3.3 hibernate的实体映射 228 4.3.4 映射一对一关联关系 228 4.3.5 映射多对一单向关联关系 235 4.3.6 映射一对多双向关联关系 239 ...

    Grails权威指南

     7.5 数据绑定和类型转换  7.5.1 用领域模型(domaincmodel)进行数据绑定  7.5.2 使用binddata方法进行数据绑定  7.6 用重定向控制流程  7.7 使用chain方法构造模型(model)  7.8 显示响应...

    Spring.3.x企业应用开发实战(完整版).part2

    《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练使用...

    Spring3.x企业应用开发实战(完整版) part1

    《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练使用...

    Struts2 in action中文版

    10.3.2 使用自定义数据验证器 229 10.4 验证框架的高级主题 230 10.4.1 在域对象级别验证 231 10.4.2 使用验证上下文优化验证 233 10.4.3 验证继承 235 10.4.4 验证短路效应 236 10.4.5 使用注解声明验证 237 10.5 ...

    北京中科信软AJAX培训

    文档类型定义及声明 XML名域 操纵和解析XML 选择合适的XML生成方式 XHTML与CSS XHTML、CSS与Ajax XHTML与CSS基础 XHTML语法约束 JavaScript JavaScript与Ajax JavaScript基本数据结构 JavaScript表达式和运算符 ...

    深入浅出Struts 2 .pdf(原书扫描版) part 1

    如数据类型转换、文件上传和下载、Struts2应用的安全性、调试与性能分析、FreeMarker、Velocily、Ajax,等等。跟随作者一道深入Struts2。聆听大量来之不易的经验之谈。你对Struts2开发框架的理解和应用水平都将更上...

    JBPM4工作流应用开始指南.rar

    120 6.2.8 自定义活动 132 6.3 自动活动 134 6.3.1 java(Java程序活动) 135 6.3.2 script(脚本活动) 139 6.3.3 hql(Hibernate查询语言活动) 144 6.3.4 sql(结构化查询语言活动) 147 6.3.5 mail(邮件活动) ...

    JAVA上百实例源码以及开源项目源代码

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    JAVA上百实例源码以及开源项目

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    java源码包---java 源码 大量 实例

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    java源码包2

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    java源码包3

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    java源码包4

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户可以在终端上...

Global site tag (gtag.js) - Google Analytics