2008-04-18
Hibernate 高级映射技术 自定义数据类型
关键字: java ee
UserType and CompositeUserType为Hibernate中提供的用户类型自定义接口。根据这个接口,可以实现自定义的数据类型。
最近在做一个博客系统的后台,设计数据库的时候考虑如何设计添加和记录好友的功能。
由于以前没有这方面的经验,所以不知道从何下手。最近看<<深入浅出Hibernate>>,作者在书中介绍了Hibernate 提供的用户自定义数据类型,于是效仿书中的方法,在数据库表中添加一个字段用于记录所有好友的userid,每个userid之间用";"加以分隔,同时将该字段映射为一个特殊的List集合,利用UserType interface实现String解析后将各个userid封装在List中,将List中的记录封装成以";"分隔的String。
使用UserType接口,实现了较好的设计风格,以及更好的重用性。
/*
* 用户自定义的数据类型,对应数据库中的一个字段,在该字段中,保存了
* 多个用户需要的信息,之间用";"加以分隔.
* @Author:Paul
* @Date:April 18th,2008
*/
package com.globalhands.hibernate.userTypes;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.sql.Types;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class SpecialList implements UserType {
private List specialList;
private static final char SPLITTER = ';';
private static final int[] TYPES = new int[] { Types.VARCHAR };
public String assemble(Serializable arg0, Object arg1)
throws HibernateException {
return null;
}
/*
* 将List封装为一个String对象
*/
public String assemble(List specialList) throws HibernateException {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < specialList.size() - 1; i++) {
sb.append(specialList.get(i)).append(this.SPLITTER);
}
sb.append(specialList.get(specialList.size() - 1));
return sb.toString();
}
/*
* 创建一个新的List实例,包含原有的List实例中的所有元素.
*/
public Object deepCopy(Object value) throws HibernateException {
List sourceList = (List) value;
List targetList = new ArrayList();
targetList.addAll(sourceList);
return targetList;
}
public Serializable disassemble(Object arg0) throws HibernateException {
return null;
}
/*
* 判断specialList是否发生变化
*/
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() - 1; i++) {
String str1 = (String) xList.get(i);
String str2 = (String) yList.get(i);
if (!xList.equals(yList)) {
return false;
}
}
return true;
}
return false;
}
public int hashCode(Object arg0) throws HibernateException {
return 0;
}
public boolean isMutable() {
return false;
}
/*
* 从resultset中取出email字段,并将其解析为List类型后返回
*/
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);
} else {
return null;
}
}
/*
* 将以";"分隔的字符串解析为一个字符串数组
*/
private List parse(String value) {
String[] strs = value.split(";");
List specialList = new ArrayList();
for (int i = 0; i <= strs.length - 1; i++) {
specialList.add(strs[i]);
}
return specialList;
}
/*
* 将List型的email信息组装成字符串之后保存到email字段
*/
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (value != null) {
String str = assemble((List) value);
Hibernate.STRING.nullSafeSet(st, str, index);
} else {
Hibernate.STRING.nullSafeSet(st, value, index);
}
}
public Object replace(Object arg0, Object arg1, Object arg2)
throws HibernateException {
return null;
}
public Class returnedClass() {
return List.class;
}
public int[] sqlTypes() {
return TYPES;
}
}
同时,修改相应的[ormapping_filename].hbm.xml中相应字段的映射信息
<property name="buddy" type="com.globalhands.hibernate.userTypes.SpecialList">
<column name="buddy" length="2000" not-null="true" />
</property>
之后,修改POJO类中该字段的返回类型为List。
使用JUnit测试程序。
最近在做一个博客系统的后台,设计数据库的时候考虑如何设计添加和记录好友的功能。
由于以前没有这方面的经验,所以不知道从何下手。最近看<<深入浅出Hibernate>>,作者在书中介绍了Hibernate 提供的用户自定义数据类型,于是效仿书中的方法,在数据库表中添加一个字段用于记录所有好友的userid,每个userid之间用";"加以分隔,同时将该字段映射为一个特殊的List集合,利用UserType interface实现String解析后将各个userid封装在List中,将List中的记录封装成以";"分隔的String。
使用UserType接口,实现了较好的设计风格,以及更好的重用性。
/*
* 用户自定义的数据类型,对应数据库中的一个字段,在该字段中,保存了
* 多个用户需要的信息,之间用";"加以分隔.
* @Author:Paul
* @Date:April 18th,2008
*/
package com.globalhands.hibernate.userTypes;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.sql.Types;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class SpecialList implements UserType {
private List specialList;
private static final char SPLITTER = ';';
private static final int[] TYPES = new int[] { Types.VARCHAR };
public String assemble(Serializable arg0, Object arg1)
throws HibernateException {
return null;
}
/*
* 将List封装为一个String对象
*/
public String assemble(List specialList) throws HibernateException {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < specialList.size() - 1; i++) {
sb.append(specialList.get(i)).append(this.SPLITTER);
}
sb.append(specialList.get(specialList.size() - 1));
return sb.toString();
}
/*
* 创建一个新的List实例,包含原有的List实例中的所有元素.
*/
public Object deepCopy(Object value) throws HibernateException {
List sourceList = (List) value;
List targetList = new ArrayList();
targetList.addAll(sourceList);
return targetList;
}
public Serializable disassemble(Object arg0) throws HibernateException {
return null;
}
/*
* 判断specialList是否发生变化
*/
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() - 1; i++) {
String str1 = (String) xList.get(i);
String str2 = (String) yList.get(i);
if (!xList.equals(yList)) {
return false;
}
}
return true;
}
return false;
}
public int hashCode(Object arg0) throws HibernateException {
return 0;
}
public boolean isMutable() {
return false;
}
/*
* 从resultset中取出email字段,并将其解析为List类型后返回
*/
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);
} else {
return null;
}
}
/*
* 将以";"分隔的字符串解析为一个字符串数组
*/
private List parse(String value) {
String[] strs = value.split(";");
List specialList = new ArrayList();
for (int i = 0; i <= strs.length - 1; i++) {
specialList.add(strs[i]);
}
return specialList;
}
/*
* 将List型的email信息组装成字符串之后保存到email字段
*/
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (value != null) {
String str = assemble((List) value);
Hibernate.STRING.nullSafeSet(st, str, index);
} else {
Hibernate.STRING.nullSafeSet(st, value, index);
}
}
public Object replace(Object arg0, Object arg1, Object arg2)
throws HibernateException {
return null;
}
public Class returnedClass() {
return List.class;
}
public int[] sqlTypes() {
return TYPES;
}
}
同时,修改相应的[ormapping_filename].hbm.xml中相应字段的映射信息
<property name="buddy" type="com.globalhands.hibernate.userTypes.SpecialList">
<column name="buddy" length="2000" not-null="true" />
</property>
之后,修改POJO类中该字段的返回类型为List。
使用JUnit测试程序。
- 22:45
- 浏览 (240)
- 论坛浏览 (1776)
- 评论 (13)
- 相关推荐
评论
chen-516888
2008-04-25
回复
谢谢大家:)
chen-516888 写道
再问一下。。。
好友对象也是User
如何让User 映射的表和自己关联???
那自己 是 inverse=false
还是 inverse=true??????
好友对象也是User
如何让User 映射的表和自己关联???
那自己 是 inverse=false
还是 inverse=true??????
inverse=true
控制权交给User好友方,自己不能随意修改和删除自己的好友信息吧。
但是自己映射好友有问题,好友方不能多对一映射自己,因为这样做的,变成对方只能做你的好友,做不了其他人了,你这个映射应该是多对多。
你自己做个user到user的多对多的配置,数据库中肯定要有个表叫user_2_user的table,这个table不需要model直接映射的,你看了多对多映射的例子就明白了,自动查这张中间表的。
chen-516888
2008-04-24
回复
再问一下。。。
好友对象也是User
如何让User 映射的表和自己关联???
那自己 是 inverse=false
还是 inverse=true??????
好友对象也是User
如何让User 映射的表和自己关联???
那自己 是 inverse=false
还是 inverse=true??????
chen-516888
2008-04-19
回复
非常感谢:)
着手重构
着手重构
chen-516888
2008-04-19
回复
那需要修改那些地方?
能不能再具体些
非常感谢!!!:)
能不能再具体些
非常感谢!!!:)
不是的。每次读取User的时候,好友列表缺省是延迟加载的。只有你需要使用好友列表的时候,才会读取好友列表对象数据。
不会加重数据库负担的。而且如果有二级缓存的话,还可以大大减轻数据库负担。
不会加重数据库负担的。而且如果有二级缓存的话,还可以大大减轻数据库负担。
chen-516888
2008-04-19
回复
那如果有100个好友的话
每次读取User的时候不是要加载100个User的实例吗?
我是想在页面中循环输出
<a src="/viewothers.do?otheruserid=<%=friendid%>">
<font><%=friendname%></font>
</a>
要看某个好友的信息
把friendid传给action
然后再从数据库中读取某一个好友的信息,调到好友的页面
每次读取User的时候不是要加载100个User的实例吗?
我是想在页面中循环输出
<a src="/viewothers.do?otheruserid=<%=friendid%>">
<font><%=friendname%></font>
</a>
要看某个好友的信息
把friendid传给action
然后再从数据库中读取某一个好友的信息,调到好友的页面
假设用户对象为User,那么它带有一个属性,用集合的方式表示好友。
就是这样。具体到数据库就会出现一张关联表
id userid friendly
* 1 2
* 1 3
你读取User的时候,就可以直接读取好友。当用户删除的时候,关联表中用户的所有好友关联也会被删除。
class User {
private Integer id;
//好友集合
private Set<User> friendly
}
就是这样。具体到数据库就会出现一张关联表
id userid friendly
* 1 2
* 1 3
你读取User的时候,就可以直接读取好友。当用户删除的时候,关联表中用户的所有好友关联也会被删除。
chen-516888
2008-04-19
回复
如何映射好友对象???
能否说具体些
本人是新手
多多执教:)
能否说具体些
本人是新手
多多执教:)
我觉得这样不怎么样。表面上看是取了个巧。这么保存可以省一个关联表。而且在读取好友列表的时候也可以减少一部分数据库查询。
但是这么做破坏了对象之间的关系。甚至破坏了数据库范式。同时,如果某个人被删除了呢?你如何维护其他人的好友列表?
查询的时候也一样。你得到的是好友id而不是好友对象。你还是要查询数据库。如果你实际上映射的是好友对象,那么你就可以直接取好友列表,Hibernate会自动帮你完成。如果你使用了二级缓存,那么取好友列表的速度甚至比从数据库直接取要快得多。
自定义类型以前最常见的是映射LOB成String或byte[],最著名的是Spring写的映射类型。
但是你这么乱用日后要吃苦头的。
但是这么做破坏了对象之间的关系。甚至破坏了数据库范式。同时,如果某个人被删除了呢?你如何维护其他人的好友列表?
查询的时候也一样。你得到的是好友id而不是好友对象。你还是要查询数据库。如果你实际上映射的是好友对象,那么你就可以直接取好友列表,Hibernate会自动帮你完成。如果你使用了二级缓存,那么取好友列表的速度甚至比从数据库直接取要快得多。
自定义类型以前最常见的是映射LOB成String或byte[],最著名的是Spring写的映射类型。
但是你这么乱用日后要吃苦头的。
我的相册
IMG_9122
共 1 张
共 1 张
最近加入圈子
最新评论
-
Spring中的事务传播机制
引用
-- by zhs861025 -
映射好友信息
自己解决了 还是谢谢
-- by lzg3267373 -
映射好友信息
你好,我遇到了一样的问题 请问你的friends表是如何映射的 给出xml文件参 ...
-- by lzg3267373 -
Hibernate 高级映射技术 ...
谢谢大家:)
-- by chen-516888 -
Hibernate 高级映射技术 ...
这个还是用关联表更好些。
-- by marcian







评论排行榜