Hibernate注释下的自定义架构实现(解决table和model的命名问题)


分类: Hibernate 2009-03-11 18:24 397人阅读 评论(0) 收藏 举报
对于Java开发人员,Hibernate 3 annotations提供了非常好的方式来展示域分层。你可以很轻松的通过Hibernate自动生成需要的数据库,带有完整的SQL脚本。
然而回到现实世界,你还需要考虑到,有时数据库管理员所使用的模糊的命名惯例。本文中,“Java Power Tools”的作者John Ferguson Smart将告诉你如何通过Hibernate自动生成数据库,而且还方便数据库管理。

Hibernate 3 注释有一种强大的持久管理数据库的方式,运用这些注释,你不需要为XML映射文件而费心,你可以设置成默认,由系统完成,从而减少了大量需要维护的代码。
Hibernate提供了强大的自动生成数据库架构的工具,因此Hibernate可以自动完成生成和更新数据库架构的操作,你也无需担心那些不可思议的SQL脚本。

第一步:更新数据库架构

用Hibernate自动更新数据库架构很容易,你所需要做的只是设置好Hibernate.hbm2ddl.auto,如示例1:

示例1:


org.hibernate.dialect.Oracle10gDialect create-drop


设置它的属性为“create-drop”,那么每次启动应用程序都会产生新的数据库,这对集成测试很有用,但是有些情况下却不需要。另一方面,如果你设置这个值是为了更新,
如果不存在数据库,Hibernate只会自动创建数据库,并更新与当前域模型匹配的所有表。

现在,在默认情况下,Hibernate将创建一套与Java类很相似的表及字段,从Java开发者的角度来看这样刚好符合要求。
考虑下面的例子:

示例2:

A simple persistent class

@Entity
public class Client implements Serializable
{
@Id@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;

}

这个类中,Hibernate在默认情况下创建SQL模式,

可以继续看示例3。

示例3:

create table Client (id bigint generated by default as identity (start with 1),firstName varchar(255),lastName varchar(255),…primary key (id));

旧的命名惯例 数据库的惯例约定有相当充分的理由存在,但是在任何情况下DBA常常要保守一些。开发者该如何做呢?

一个简单的解决办法是使用名字特征:@Entity、@Column注释,这种方法优于默认情况下,如示例4:

示例4:
@Entity(name=”T_CLIENT”)public class Client implements Serializable
{

@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name=”CLIENT_ID”)
private Long id;

@Column(name=”FIRST_NAME”)
private String firstName;

@Column(name=”LAST_NAME”)
private String lastName;


}

这样很有作用,但是会有些麻烦,你不得不有更多的表。
实际上,你必须对每个表及字段都做这样的操作。

有没有更好的方法呢?
当然,你可以在Hibernate会话中定义命名策略集合取代默认值。
这样的话你得写一个类,说明Hibernate如何定义表及字段名。
从ImprovedNamingStrategy类开始是一个恰当位置,用下划线转换类名,如SomeDomainEntity,转换成some_domain_entity。
在启动Hibernate会话时需准备这个类。如果你用,需简化创建命名策略bean并为命名策略集合提供所创建的命名策略。

示例5就是配置的典型说明:

示例5:

class=”org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean”>

在这种命名策略下,Hibernate将生成如下面示例6的脚本:

示例6:
create table client (id bigintgenerated by default as identity (start with 1),first_name varchar(255),last_name varchar(255),…primary key(id));

这样虽然很好,但是它不能解决你所的。还需要数据库命名约定。

例如,每个表都可能从“T_”开始(比如T_CLIENT就是Client类),或者表中的每个字段可能以表中特定的前缀开始(比如写成CLI_FIRST_NAME和CLI_LAST_NAME)。
为了能自动生成这些约束,你写自己的命名策略实施。自定义命名策略实现自定义命名策略最简单的方法是扩展ImprovedNamingStrategy类。
这个类提供一些用户默认的情况,因此你只需实现你真正需要的方法就可以。你可以不去理睬通用样式任务的表名和列名方法,比如,把名称都加上大写字母。
Hibernate生成表或列名时就会调用这种方法,甚至是在注释中明确指定的列名也会调用这种方法。,

从ImprovedNamingStrategy类继承而来的addUnderscores()方法,可以派上用场,如示例7所示:

示例7:

public class MyNamingStrategy extends ImprovedNamingStrategy implements NamingStrategy
{
@Override
public String columnName(String columnName){
return addUnderscores(columnName).toUpperCase();
}

@Override
public String tableName(String tableName) {
return addUnderscores(tableName).toUpperCase();
}
}

接下来的示例8,展现的是如何在表名前加“T_”前缀,转换成名字前加大写字母和下划线。

示例8:

@Override
public String classToTableName(String className) {
return “T_” + tableName(className);
}

@Override
public String propertyToColumnName(
String propertyName) {
return addUnderscores(propertyName).toUpperCase();
}

一个更复杂的命名策略命名策略接口实际上非常简单,但在很多方面受限制。
首先,在任何特定的时间你无法知道调用方法的参数是属于哪个表。
这样会受限制,比如,如果需要在表中每个列名前加表前缀,正如数据库约定所要求的。
可以在classToTableName()方法中加变量成员存储当前的表,来解决这个限制。对于给定的表,这个方法将在propertyToColunmName()方法后被调用。

例如,示例9为表创建了三个字母的前缀,加在表名及表中所有列名前。

示例9:

public class MyNamingStrategy extends ImprovedNamingStrategy implements NamingStrategy {

private String currentTablePrefix;

@Override
public String classToTableName(String className) {
currentTablePrefix = className.substring(0, 3).toUpperCase() + “_”$$return “T” +
currentTablePrefix + tableName(className);
}

@Override
public String propertyToColumnName(String propertyName) {
return currentTablePrefix + addUnderscores(propertyName).toUpperCase();
}

@Override
public String columnName(String columnName) {
return addUnderscores(columnName).toUpperCase();
}

@Override
public String tableName(String tableName) {
return addUnderscores(tableName).toUpperCase();
}
}

使用这种命名策略,Hibernate将产生如示例10的代码:

示例10:
create table TCLI_CLIENT (CLI_ID bigint generated by default as identity (start with 1),CLI_FIRST_NAME varchar(255),CLI_LAST_NAME varchar(255),…primary key (CLI_ID));

外部关键字一般很难自动生成的外部关键字,构成了一个麻烦的。默认情况下,Hibernate可随机生成如“FKAB1273D65CCF7AB”这样的名字,DBA不会喜欢这样自动产生的命名。

解决这个,需要使用@ForeignKey注释,如示例11所示:

示例11:

@Entity
public class Order {

@JoinColumn(name = “CLIENT_ID”)
@ManyToOne(optional = false)
@ForeignKey(name = “FK_CLIENT_ORDERS”)
private Client client;


}

多对多关系当然,复杂的关系下(比如多对多的关系),上面所说的变得有些更复杂。

例如,示例12中的SocialNerworker类,有许多朋友。这种情况下,你需要使用像@JoinTable,@ForeignKey这样的注释。

示例12:

@Entity
public class SocialNetworker {

@ManyToMany@JoinTable(name = “TFRD_FRIEND”,joinColumns = {@JoinColumn(name = “NETWORKER_ID”)},inverseJoinColumns = {@JoinColumn(name = “FRIEND_ID”) })
@ForeignKey(name = “FK_SNT_FRIENDS”, inverseName=”FK_FRD_FRIENDS”)}
private Set friends = new HashSet ();

}

展示SQL脚本一旦你需要对数据库做改动或更新时,数据库管理员出于职责会很谨慎,可能会看要执行的SQL脚本,Hibernate可以通过SchemaExport工具,展示SQL脚本。
你使用这个工具把要完成的模式生成普通的SQL脚本。当然,此类操作你不想做为构建过程的一部分去做,如果使用

例如,你使用Hibernate3--plugin自动生成数据库架构。关键部分如示例13所示,当然你可以设置drop和export为false,这样就相当于没有更新数据库资料。

示例13: org.codehaus.mojo
hibernate3--plugin
2.1

process-classes
hbm2ddl






hbm2ddl
annotationconfiguration


hbmdoc



/target/classes/hibernate.cfg.xml

schema.ddl
mycompany.myapp.IRDNamingStrategy
false
true
false
true

这样会生成SQL脚本,可以拿给DBA们看了。总结DBA命名惯例保留了下来,如果你将与他们共事,将需要顾及这些惯例。幸运的是,这并不意味着你要放弃Hibernate自动产生的数据库架构,也不用自已写SQL脚本。用相结合的命名策略,你会获得双赢。

JDK5.0中增加了新的功能annotation,基本的意思是可以执行代码中的@*****语句,具体怎样使用请查看资料,本文中的方法是基于JDK5.0的平台,同时要下载Hibernate包中的hibernate-annotations-3.3.0.GA,将其中的*.jar加入到你的classpath中

要使用annotation,先要修改你的HibernateUtil类,请看:

sessionFactory= new Configuration().configure().buildSessionFactory();

修改为:

sessionFactory = new

AnnotationConfiguration().configure().buildSessionFactory();

同样要修改你的pojo:

@Enumerated(EnumType.STRING)

public Gender getGender() {

return gender;

}

只要修改get***()即可。

同时要导入:

Impport javax.persistence.EnumType

最后别忘了一个基本的注册修改:

在原先的hibernate.cfg.xml中要注册一个pojo采用这样的方式:

采用annotation后改为:

通过以上步骤就可以简化enum,对比方法一,方法二只是由hibernate-annotations实现了hibernate中的EnumType.方法一是由程序员自己来实现。

声明: 除非转自他站(如有侵权,请联系处理)外,本文采用 BY-NC-SA 协议进行授权 | 智乐兔
转载请注明:转自《Hibernate注释下的自定义架构实现(解决table和model的命名问题)
本文地址:https://www.zhiletu.com/archives-330.html
关注公众号:智乐兔

赞赏

wechat pay微信赞赏alipay pay支付宝赞赏

上一篇
下一篇

相关文章

在线留言

你必须 登录后 才能留言!

在线客服
在线客服 X

售前: 点击这里给我发消息
售后: 点击这里给我发消息

智乐兔官微