- 浏览: 7254010 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (1546)
- 企业中间件 (236)
- 企业应用面临的问题 (236)
- 小布Oracle学习笔记汇总 (36)
- Spring 开发应用 (54)
- IBatis开发应用 (16)
- Oracle基础学习 (23)
- struts2.0 (41)
- JVM&ClassLoader&GC (16)
- JQuery的开发应用 (17)
- WebService的开发应用 (21)
- Java&Socket (44)
- 开源组件的应用 (254)
- 常用Javascript的开发应用 (28)
- J2EE开发技术指南 (163)
- EJB3开发应用 (11)
- GIS&Mobile&MAP (36)
- SWT-GEF-RCP (52)
- 算法&数据结构 (6)
- Apache开源组件研究 (62)
- Hibernate 学习应用 (57)
- java并发编程 (59)
- MySQL&Mongodb&MS/SQL (15)
- Oracle数据库实验室 (55)
- 搜索引擎的开发应用 (34)
- 软件工程师笔试经典 (14)
- 其他杂项 (10)
- AndroidPn& MQTT&C2DM&推技术 (29)
- ActiveMQ学习和研究 (38)
- Google技术应用开发和API分析 (11)
- flex的学习总结 (59)
- 项目中一点总结 (20)
- java疑惑 java面向对象编程 (28)
- Android 开发学习 (133)
- linux和UNIX的总结 (37)
- Titanium学习总结 (20)
- JQueryMobile学习总结 (34)
- Phonegap学习总结 (32)
- HTML5学习总结 (41)
- JeeCMS研究和理解分析 (9)
最新评论
-
lgh1992314:
[u][i][b][flash=200,200][url][i ...
看看mybatis 源代码 -
尼古拉斯.fwp:
图片根本就不出来好吧。。。。。。
Android文件图片上传的详细讲解(一)HTTP multipart/form-data 上传报文格式实现手机端上传 -
ln94223:
第一个应该用排它网关吧 怎么是并行网关, 并行网关是所有exe ...
工作流Activiti的学习总结(八)Activiti自动执行的应用 -
ZY199266:
获取不到任何消息信息,请问这是什么原因呢?
ActiveMQ 通过JMX监控Connection,Queue,Topic的信息 -
xiaoyao霄:
DestinationSourceMonitor 报错 应该导 ...
ActiveMQ 通过JMX监控Connection,Queue,Topic的信息
在项目中许多地方使用枚举类,枚举对象值对应数据一个常量。增加代码的可读性等。具体使用如下:
JPA参考手册:JPA注释参考手册 http://www.oidn.net/blog/article.asp?id=250
Hibernate Annotation 用户类型(User Type)
使用UserType首先要弄清楚它的目的。大家知道Hibernate解决的主要是对象数据库阻抗失衡的问题,也就是如何将一个或多个对象保存到一个或多个数据库表格中。
这其中有很多方法,其实大部分情况下采用@Embeddable和 @Embedded 就可以解决问题了,只有嵌入对象方式无法满足要求时,或者是Hibernate默认的持久化方式无法满足要求时,才应该考虑UserType。
总之记住一 个原则,不到山穷水尽,不要轻易使用UserType。还有一个要慎重考虑使用UserType的原因是:一旦采用了UserType,你的项目就脱离了 JPA,而直接和Hibernate耦合在一起了。
扩展UserType主要分为两种:
- immutable
- mutable
今天我先举个immutable的例子。
Java 5提出了一个新的enum类,JPA提供的标准方法是保存enum的name或者是ordinal。这种默认方式能够满足新开发的项目,但是对于一些老项目翻新并不一定适用。下面我们来看一个例子:
public static final int ACTIVATED = 5 ;
public static final int DEACTIVATED = 6 ;
}
这个是在java5之前常用的常量定义方法,老项目数据库里面已经保存了很多的5啊6的。现在要把Status改写成enum,而且不希望修改数据库中已有的数据,怎么做?第一反应,status enum可以这么写:
ACTIVATED,
DEACTIVATED;
}
持久化enum的name属性是肯定不用考虑了,ordinal属性呢?这里要保存的可是5和6,而Status enum只有两个实体,他们的ordinal只是0和1。而且项目中还会有其他很多类似的常量类需要改写成enum,JPA的默认方式无法完成任务,这时 候可以开始考虑使用UserType了。
先定义一个接口,这样可以使用一个UserType支持所有类似的enum:
String getDescription();
int getId();
}
然后改写Status enum:
ACTIVATED( 5 , " This object is activated " ),
DEACTIVATED( 9 , " This object is deactivated " );
private Integer id;
private String description;
private static List < Status > list;
static {
list = new ArrayList < Status > ( 2 );
list.add(ACTIVATED);
list.add(DEACTIVATED);
}
private Status( int statusNr, String description) {
this .id = statusNr;
this .description = description;
}
public String getDescription() {
return this .description;
}
public Integer getId() {
return id;
}
public static List < Status > getAll() {
return list;
}
public static Status findById(Integer id) {
for (Status status : getAll()) {
if (id == status.getId()) {
return status;
}
}
return null ;
}
}
注意这里每个enum都必须有两个static方法,这些方法名必须在所有的enum中保持一致。
List()方法是为了方便获取所有的Status常 量,例如在用户界面通过ComboBox展示,findById()方法是为了通过给定Id获得对应的Enum实例。其中findById()方法参数一 定要是Integer,原因后面会讲到。
下面编写DescriptionIDUserType:
public class DescriptionIDUserType implements UserType, ParameterizedType {
private Class enumClass;
public void setParameterValues(Properties parameters) {
try {
enumClass = ReflectHelper.classForName(parameters.getProperty( " class " ));
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Object assemble(Serializable cached, Object arg1)
throws HibernateException {
return cached;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
*/
public Object deepCopy(Object value) throws HibernateException {
// TODO Auto-generated method stub
return value;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
*/
public Serializable disassemble(Object value) throws HibernateException {
// TODO Auto-generated method stub
return (Serializable) value;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#equals(java.lang.Object,
* java.lang.Object)
*/
public boolean equals(Object id1, Object id2) throws HibernateException {
if (id1 == id2) {
return true ;
}
if (id1 == null || id2 == null ) {
return false ;
}
final DescriptionID did1 = (DescriptionID) id1;
final DescriptionID did2 = (DescriptionID) id2;
return did1.getId() == did2.getId()
&& StringUtils.equals(did1.getDescription(), did2
.getDescription());
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
*/
public int hashCode(Object value) throws HibernateException {
// TODO Auto-generated method stub
return value.hashCode();
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#isMutable()
*/
public boolean isMutable() {
// TODO Auto-generated method stub
return false ;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet,
* java.lang.String[], java.lang.Object)
*/
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
throws HibernateException, SQLException {
try {
int id = resultSet.getInt(names[ 0 ]);
if (resultSet.wasNull()) {
return null ;
}
return enumClass.getMethod( " findById " , new Class[] { Integer. class })
.invoke( null , id);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null ;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement,
* java.lang.Object, int)
*/
public void nullSafeSet(PreparedStatement statement, Object value, int index)
throws HibernateException, SQLException {
if (value == null ) {
statement.setNull(index, Hibernate.INTEGER.sqlType());
} else {
DescriptionID dID = (DescriptionID) value;
statement.setInt(index, dID.getId());
}
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#replace(java.lang.Object,
* java.lang.Object, java.lang.Object)
*/
public Object replace(Object original, Object arg1, Object arg2)
throws HibernateException {
// TODO Auto-generated method stub
return original;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#returnedClass()
*/
public Class returnedClass() {
return DescriptionID. class ;
}
/*
* (non-Javadoc)
*
* @see org.hibernate.usertype.UserType#sqlTypes()
*/
public int [] sqlTypes() {
return new int []{Hibernate.INTEGER.sqlType()};
}
}
我们的这个UserType是要支持实现DescriptionID的各种不同的enum,而enum是没法继承的。所以我们需要用户给出具体的参数,以进一步确定到底是哪个enum类。这也就导致了,我们的这个类需要实现 ParameterizedType接口。
由于enum类本身是immutable的,所以这个UserType的实现类相对比较简单,主要的两个方法是 nullSafeGet和 nullSafeSet。
在nullSaftGet中我们使用Java Reflection并借助用户给出的enum类参数直接调用该enum类的findById()方法,这样我们就可以使用数据库中的integer找到 对应的enum实例。
注意,由于使用了Java Reflection,所以findById()方法参数必须是Integer而非int。 在nullSafeSet中,我们则通过 DescriptionID接口直接获取enum实例的id属性,并且将它保存到数据库中去。
最后看看怎么使用这个UserType:
parameters = {@Parameter(name = " class " , value = " com.yourpackage.Status " )})})
@Entity
public class SomeObject {
private Integer objectId;
private Status status;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public Integer getObjectId() {
return objectId;
}
public void setObjectId(Integer objectId) {
this .objectId = objectId;
}
@Type(type = " status " )
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this .status = status;
}
}
其中值得讲讲的就是定义Type时使用的parameter,"class"参数是我们自己定义的,该参数为DescriptionIDUserType提供 了具体的enum类。前面已经讲过了,DescriptionIDUserType就是在运行时态利用这个参数自定义enum与数据库之间的持久化逻辑。
使用这个UserType之后,我们就可以在确保数据库数据不变的情况下,成功地将类型不保险的常量类改写成enum,而且这个UserType支持所有实现了 DescriptionID接口的enum类。
发表评论
-
编程的十四条经验
2013-05-06 10:32 1795排列不分先后: 1. 当 ... -
整合Struts2+JasperReport Web报表应用示例
2013-04-22 13:56 2249整合Struts2+JasperReport Web报表应用 ... -
关于H2使用的那些事
2012-12-14 16:40 27079在项目中采用H2作为工 ... -
Java 分割功能实现
2011-08-25 08:39 2744在项目针对比较大的文件需要文件的分割功能,特意写了一个 ... -
反射工具类
2010-04-25 10:47 2352package easyway.tbs.client.bm.u ... -
项目中Hibernate中Criteria和Query查询和模式引用
2010-02-21 15:52 2399在项目中Hibernate中Criteria和Q ... -
json 在项目中开发一个巧妙地应用
2009-12-12 16:49 3866在项目中需要保存客户的信息到Cookie中,因为客户要求 ... -
项目中使用时间工具类
2009-11-21 16:43 2991项目中使用的时间工具类的主要的采用commons-l ... -
将HTML文件转换为图片应用开发
2009-10-21 11:15 4408项目使用的基 ... -
Spring项目的测试用例
2009-08-22 12:49 2290在项目的开发过程中使用Junit4测试代码,使用 ... -
jBPM与Spring整合浅析
2009-08-22 12:41 26321、创建公文流转相关的实体类,并创建数据库表 2、根据对用 ... -
Hibernate正向工程hbm2ddl
2009-08-19 10:14 2261一般在项目开 ... -
关于常用城市控件中数据的处理方案
2009-08-15 19:41 2366在项目中由于多次使用的国家省份城市的控件,以前采 ... -
在Spring2.5注解时必须注意几点
2009-08-15 19:22 2095项目中采用Spring2.5配置重点内容如下: ... -
中文转换拼音的实现思路以及实现
2009-08-15 18:40 2836在项目中一位大师兄写的中文转换拼音代码:自己整理一下 ... -
在项目中一些相关常量数组使用枚举应用
2009-08-15 18:01 2559在项目中采用Hibernate中支持枚举类型因此我们使用许 ... -
在项目开发中关于Hibernate注解的配置的一些说明
2009-08-15 13:26 4312在项目开发中采用Hibernate3注解方式实现关 ... -
关于项目中泛型的应用
2009-08-15 12:38 2350在项目采用JDK1.6采用泛型开发,在开发应用之中减少了大 ... -
针对项目中XML解析的扩展应用
2009-08-15 12:14 2543由于项目中多个需 ...
相关推荐
12.6 整合Struts、Spring和Hibernate实现用户管理 12.6.1 Struts、Spring和Hibernate的整合方式 12.6.2 编写用户注册画面regedit.jsp 12.6.3 编写用户登录画面login.jsp 12.6.4 编写注册控制器RegeditAction.java ...
12.6 整合Struts、Spring和Hibernate实现用户管理 12.6.1 Struts、Spring和Hibernate的整合方式 12.6.2 编写用户注册画面regedit.jsp 12.6.3 编写用户登录画面login.jsp 12.6.4 编写注册控制器RegeditAction.java ...
12.6 整合Struts、Spring和Hibernate实现用户管理 12.6.1 Struts、Spring和Hibernate的整合方式 12.6.2 编写用户注册画面regedit.jsp 12.6.3 编写用户登录画面login.jsp 12.6.4 编写注册控制器RegeditAction.java ...
sessionFactory 用的,里面主要包含了数据库连接相关东西,还有 java 类所对应的别名,比如 <typeAlias alias="User" type="com.yihaomen.mybatis.model.User"/> 这个别名非常重要,你在 具体的类的映射中,比如User...
在java中使用套接口相当简单,Java API为处理套接口的通信提供了一个类java.net.Socket,使得编写网络应用程序相对容易。服务器采用多线程以满足多用户的请求,并通过创建一个ServerSocket对象来监听来自客户的连接...
创建测试数据库,并在数据库中创建一个t_user 表,其中包含三个字段: . id(int) . name(varchar) . sex(int) 。 3. 为了在开发过程更加直观,我们需要将ibatis 日志打开以便观察ibatis 运作的细节...
12.6 整合Struts、Spring和Hibernate实现用户管理 12.6.1 Struts、Spring和Hibernate的整合方式 12.6.2 编写用户注册画面regedit.jsp 12.6.3 编写用户登录画面login.jsp 12.6.4 编写注册控制器RegeditAction.java ...
} else if (InvokeType.userDefined == type) { if (StringUtils.isBlank(listStyle)) { throw new ParamsRequiredException(PARAM_STYLE_LIST); } //列表样式模板路径 WEB-INF\t\cms_sys_defined\style_list\...
2.9 如何清除Hibernate Session中的对象 22 2.10 使用日期控件 22 2.11 如何引入外部文件 23 2.11.1 主页面采用include方式,引入各个子页面jsp文件 23 2.11.2 主页面用${ctx}方式,引入超链接或资源文件等。 23 ...
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...
仅仅通过反射方法没有办法知道集合元素中的类型,所以上面的两个converter能将任何集合转换成相对javascript而言有意义的对象.然而没有办法将不同的集合类类型分别采用不同的转换方法.因为没有办法完全自动进行转换,...
用户相关配置和仓库 2.5.2. 升级Maven 2.6. 获得Maven帮助 2.7. 使用Maven Help插件 2.7.1. 描述一个Maven插件 2.8. 关于Apache软件许可证 I. Maven实战 3. 一个简单的Maven项目 3.1. 简介 3.1.1. ...
10, 10, java.awt.image.BufferedImage.TYPE_INT_RGB); java.awt.Graphics2D g = bufferedImage.createGraphics(); g.drawLine(0, 0, 10, 10); g.dispose(); supportImageProcessing = true; } catch (Throwable ex...