Hibernate中的自己定义类型——UserType、CompositeUserType
一、UserType
Hibernate拥有自己定义映射表属性的机制。主要通过实现接口UserType,详细的UserType:
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import net.sf.hibernate.HibernateException; /**
* @author hy-he
*
*/
public interface UserType { /**
* 返回UserType所映射字段的SQL类型(java.sql.Types)
* 返回类型为int[],当中包括了映射个字段的SQL类型代码
* (UserType能够映射到一个或者多个字段)
* @return
*/
public int[]sqlTypes(); /**
* UserType.nullSafeGet()所返回的自己定义数据类型
* @return
*/
public Class returnedClass(); /**
* 自己定义数据类型的比对方法
* 此方法将用作脏数据检查。參数x、y分别为数据的两个副本
* 假设equals方法返回false,则Hibernate将觉得数据发生变化,并将变化更新到数据库表中
* @param x
* @param y
* @return
* @throws HibernateException
*/
public boolean equals(Object x,Object y)throws HibernateException; /**
* 从JDBC ResultSet读取数据,将其转换为自己定义类型后返回
* (此方法要求对克能出现null值进行处理)
* names中包括了当前自己定义类型的映射字段名称
* @param rs
* @param names
* @param owner
* @return
* @throws HibernateException
* @throws SQLException
*/
public Object nullSafeGet(ResultSet rs,String[] names,Object owner)throws HibernateException,SQLException; /**
* 本方法将在Hibernate进行数据保存时被调用
* 我们能够通过PreparedStateme将自己定义数据写入到相应的数据库表字段
* @param st
* @param value
* @param index
* @throws HibernateException
* @throws SQLException
*/
public void nullSafeSet(PreparedStatement st,Object value,int index)throws HibernateException,SQLException; /**
* 提供自己定义类型的全然复制方法
* 本方法将用构造返回对象
* 当nullSafeGet方法调用之后,我们获得了自己定义数据对象。在向用户返回自己定义数据之前,
* deepCopy方法将被调用。它将根据自己定义数据对象构造一个全然拷贝。并将此拷贝返回给用户
* 此时我们就得到了自己定义数据对象的两个版本号,第一个是从数据库读出的原始版本号。其二是我们通过
* deepCopy方法构造的复制版本号,原始的版本号将有Hibernate维护,复制版由用户使用。原始版本号用作
* 稍后的脏数据检查根据;Hibernate将在脏数据检查过程中将两个版本号的数据进行对照(通过调用
* equals方法)。假设数据发生了变化(equals方法返回false),则运行相应的持久化操作
*
* @param value
* @return
* @throws HibernateException
*/
public Object deppCopy(Object value)throws HibernateException; /**
* 本类型实例是否可变
* @return
*/
public boolean isMutable();
}
样例:一个学生有联系地址。而联系地址又分为家庭地址和工作地址,我们能够把两个地址信息抽象成一个新的Address类。作为Student的成员变量。
数据库结构:
create table typestu (id varchar(32) primary key,name varchar(32),homeaddr varchar(32),workaddr varchar(32));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">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/schoolproject?characterEncoding=gb2312&useUnicode=true
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="myeclipse.connection.profile">mysql</property>
<property name="connection.password">1234</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.show_sql">true</property>
<property name="current_session_context_class">thread</property>
<mapping resource="Search/UserType/Student.hbm.xml" />
</session-factory>
</hibernate-configuration>Pojo
package Search.UserType;

public class Student {
private String id; //标识id
private String name; //学生姓名
private AddressType address;//地址
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AddressType getAddress() {
return address;
}
public void setAddress(AddressType address) {
this.address = address;
}
}
自己定义类型

package Search.UserType;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class AddressType implements UserType, Serializable {
private String homeAddr;
private String workAddr;
/* 有几个字段就有几个值,这里easy出错。要多注意 */
private static final int[] SQL_TYPES = { Types.VARCHAR, Types.VARCHAR };
/* 这种方法告诉Hibernate在成生DDL时对列採用什么样的SQL语法 */
public int[] sqlTypes() {
return SQL_TYPES;
}
/*
* Hibernate返回什么样的映射类型。与 <property name="address" type="model.AddressType">
* 指定的类一致。其实也能够把AddressType拆分为两个类,一个类是仅仅携带信息的JavaBean,它里面
* 没有逻辑操作也没有实现UserType(比方AddressBean)。而还有一个类实现了UserType。它所面对的就不是如今这个
* AddressType类的homeAddr和homeAddr属性,它面对的是AddressBean。在本例中为了简洁方便。仅仅用了一个类。
*/
public Class returnedClass() {
return AddressType.class;
}

/*
* 表明这个类的实例在创建以后就不能够改变属性。Hibernate能为不可改变的类作一些性能优化。
*/
public boolean isMutable() {
return false;
}

/*
* 因为AddressType是不可变的,所以深拷贝能够直接返回对象引用。
拷贝的对象由应用程序使用。 而原版对象由Hibernate维护以做脏数据检查
*/
public Object deepCopy(Object value) {
return value; // Address is immutable
}

/* 两个对象是否相等,使用了apache的common工具包来进行属性比对 */
public boolean equals(Object x, Object y) {
if (x == y)
return true;
if (x == null || y == null)
return false;
AddressType add1 = (AddressType) x;
AddressType add2 = (AddressType) y;
return new EqualsBuilder() //使用EqualsBuilder类来方便地进行比对
.append(add1.getHomeAddr(), add2.getHomeAddr()).append(
add2.getWorkAddr(), add2.getWorkAddr()).isEquals();
}

/* 得到hash码 */

public int hashCode(Object x) throws HibernateException {
AddressType address = (AddressType) x;
return new HashCodeBuilder()//使用HashCodeBuilder类来方便地进行比对
.append(address.getHomeAddr()).append(address.getWorkAddr())
.toHashCode();
}

/* 读取数据并组装成一个AddressType对象。
names[]中的參数顺序按照映射文件里定义的顺序 */
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
if (rs.wasNull())
return null;
String homeAddr = rs.getString(names[0]);
String schoolAddr = rs.getString(names[1]);
AddressType address = new AddressType(homeAddr, schoolAddr);
return address;
}

/* 保存数据。index的顺序依照映射文件定义的顺序。从0開始。 */
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
AddressType address = (AddressType) value;
if (value == null) {
st.setNull(index, Types.VARCHAR);
st.setNull(index+1, Types.VARCHAR);
} else {
st.setString(index, address.getHomeAddr());
st.setString(index + 1, address.getWorkAddr());
}
System.out.println("Data has been saved! ");
}

/* 当把AddressType类型数据写入二级缓存时,此方法被调用 */
public Serializable disassemble(Object value) throws HibernateException {
return null;
}

/* 当从二级缓存中读取AddressType类型数据时。此方法被调用 */
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
// TODO 自己主动生成方法存根
return null;
}

public Object replace(Object original, Object target, Object owner)
throws HibernateException {
// TODO 自己主动生成方法存根
return null;
}

public AddressType() {
super();
}

public AddressType(String homeAddr, String workAddr) {
super();
this.homeAddr = homeAddr;
this.workAddr = workAddr;
}

/**
* @return 返回 sQL_TYPES。
*/
public static int[] getSQL_TYPES() {
return SQL_TYPES;
}

/**
* @return 返回 homeAddr。
*/
public String getHomeAddr() {
return homeAddr;
}

/**
* @param homeAddr
* 要设置的 homeAddr。
*/
private void setHomeAddr(String homeAddr) {
this.homeAddr = homeAddr;
}

private String getWorkAddr() {
return workAddr;
}

private void setWorkAddr(String workAddr) {
this.workAddr = workAddr;
}





}

Student.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">
<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
<class name="Search.UserType.Student" table="typestu" lazy="false">
<id name="id" unsaved-value="null" type="string" column="id">
<generator class="uuid.hex" />
</id>
<property name="name" type="string" />
<property name="address" type="Search.UserType.AddressType">
<column name="homeaddr"/>
<column name="workaddr"/>
</property>
</class>
</hibernate-mapping>

測试代码:
package Search.UserType;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Blob;
import java.sql.Clob;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class Test {

public static void main(String[] args) {
String filePath=System.getProperty("user.dir")+File.separator+"src/Search/UserType"+File.separator+"hibernate.cfg.xml";
File file=new File(filePath);
SessionFactory sessionFactory=new Configuration().configure(file).buildSessionFactory();
Session session=sessionFactory.openSession();
Transaction tx=session.beginTransaction();
AddressType address=new AddressType("home","work");
Student stu=new Student();
stu.setName("tome1");
stu.setAddress(address);
session.save(stu);
tx.commit();

}
}
二、CompositeUserType
CompositeUserType拥有UserType全部的接口,并提供了更加丰富的功能。能够实现更加复杂的功能。
待续...
Hibernate中的自己定义类型——UserType、CompositeUserType的更多相关文章
- Hibernate 多表关联映射- Hibernate中使用的集合类型(set,list,array,bag,map)
Set类型的使用: <hibernate-mapping package="cn.model"> <class name="Department&quo ...
- Hibernate中使用的集合类型
department与employee是一对多关系. set <set name="emps" inverse="true"> <key co ...
- hibernate Java 时间和日期类型的 Hibernate 映射
基础知识: 在 Java 中, 代表时间和日期的类型包含: java.util.Date 和 java.util.Calendar. 此外, 在 JDBC API 中还提供了 3 个扩展了 java. ...
- hibernate Java 时间和日期类型 Hibernate 制图
基础知识: 于 Java 于, 型表示的时间和日期包含: java.util.Date 和 java.util.Calendar. 外, 在 JDBC API 中还提供了 3 个扩展了 java.ut ...
- hibernate中java类的成员变量类型如何映射到SQL中的数据类型变化
hibernate映射文件??.hbm.xml配置映射元素详解--Hibernate映射类型 在从Hibernate的java的成员类型映射到SQL中的数据类型,其内映射方式它满足,SQL可以自己调制 ...
- [原创]java WEB学习笔记81:Hibernate学习之路--- 对象关系映射文件(.hbm.xml):hibernate-mapping 节点,class节点,id节点(主键生成策略),property节点,在hibernate 中 java类型 与sql类型之间的对应关系,Java 时间和日期类型的映射,Java 大对象类型 的 映射 (了解),映射组成关系
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Java中返回值定义为int类型的 方法return 1返回的是int还是Integer&&finally中return问题
在Java中返回值定义为int类型的 方法return 1:中返回的是Integer值,在返回的时候基本类型值1被封装为Integer类型. 定义一个Test类,在异常处理try中和finally中分 ...
- 在Hibernate中配置Hilo进行数据绑定测试时出错:org.hibernate.MappingException: Could not instantiate id generator
在进行学习具体类单表继承时使用hilo类型时总是在调度过程中提示如下信息,无法通过.留下记录备查. 在网上找相关信息, 未解决,详细如下: org.hibernate.MappingException ...
- Hibernate中Criteria的完整用法
1,CriteriaHibernate 设计了 CriteriaSpecification 作为 Criteria 的父接口,下面提供了 Criteria和DetachedCriteria .2,De ...
随机推荐
- easyui权限管理
在easyui上实现权限的管理 所谓权限:指的是系统中的资源,资源包括菜单资源(学习情况报表,账号审核...)以及按钮资源所谓角色:指的是系统中的权限集合(每一个角色对应着哪些权限集合) 1.一星权限 ...
- github 从一个仓库换到另一个仓库
1.找到.git目录 2.打开config文件 3.修改仓库地址 4.重新提交 git push --all origin 这样就替我们的项目换仓啦!!!^_^
- [bzoj4899]记忆的轮廓 题解(毒瘤概率dp)
题目背景 四次死亡轮回后,昴终于到达了贤者之塔,当代贤者夏乌拉一见到昴就上前抱住了昴“师傅!你终于回来了!你有着和师傅一样的魔女的余香,肯定是师傅”.众所周知,大贤者是嫉妒魔女沙提拉的老公,400年前 ...
- 前端 (cookie )页面进入存储一次
<!--引入jq--> <script> var isShowTip = window.sessionStorage.getItem("isShow") ...
- vue获取v-model数据类型boolean改变成string
问题描述 今天产品问我一线上bug,怎么radio类型改不了 问题分析 看代码,之前的哥们儿是怎么写的 //页面 <div class="ui-form-box"> & ...
- JavaScript中通过原型添加方法,解决数据共享问题,节省内存空间
涉及知识点:(1)原型的引入(2)构造函数.原型对象和实例对象之间的关系(3)__proto__和prototype的理解 直接举例:在自定义构造函数创建对象时,因为创建的对象使用的不是同一个方法,所 ...
- php微信公众号开发之快递查询
[文章来源:脚本之家 文章地址:https://www.jb51.net/article/149205.htm] 本文实例为大家分享了php微信公众号开发之快递查询的具体代码,供大家参考,具体内容 ...
- mysql5.7zip安装
一.下载mysql zip文件 二.解压.(我的目录A:\mysql\mysql-5.7.23-winx64) 三.配置环境变量 Path后面追加%A:\mysql\mysql-5.7.23-wi ...
- InnoDB INFORMATION_SCHEMA Metrics Table
InnoDB INFORMATION_SCHEMA Metrics Table INNODB_METRICS表将所有InnoDB性能和资源相关计数器合并到一个INFORMATION_SCHEMA表中. ...
- tomcat7使用dbcp连接池遇到的坑
项目部署在tomcat后每隔一段时间便会报错 Cause: java.sql.SQLException: Could not retrieve transation read-only status ...