修改hibernate生成数据库的命名规则

本文介绍如何使用Hibernate3注释来自动生成数据库架构,并调整以符合DBA的命名规范。

  

2012-03-27 13:55:25|  分类: 默认分类|举报|字号 订阅

对于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: 

<hibernate-configuration> 
   <session-factory>       
      <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property> 
      <property name="hibernate.hbm2ddl.auto">create-drop</property> 
      ... 
      <!-- Persistent classes --> 
      <mapping class="com.mycompany.myapp.domain.Client"/> 
      <mapping class="com.mycompany.myapp.domain.Order"/> 
      ... 
   </session-factory>   
</hibernate-configuration> 
设置它的属性为“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会话时需准备这个类。如果你用Spring,需简化创建命名策略bean并为命名策略集合提供所创建的命名策略。 
示例5就是Spring配置的典型说明: 
示例5: 
<bean id="sessionFactory" 
           class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
       <property name="dataSource" ref="dataSource" /> 
       <property name="configLocation" value="classpath:/hibernate.cfg.xml" /> 
       <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /> 
       <property name="namingStrategy" ref="namingStrategy" /> 
    </bean>   

    <bean id="namingStrategy" class="org.hibernate.cfg.ImprovedNamingStrategy"/> 
在这种命名策略下,Hibernate将生成如下面示例6的脚本: 
示例6: 
create table client ( 
        id bigint generated 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<SocialNetworker> friends = new HashSet<SocialNetworker>(); 
        ... 
    } 

展示SQL脚本 
一旦你需要对数据库做改动或更新时,数据库管理员出于职责会很谨慎,可能会看要执行的SQL脚本,Hibernate可以通过SchemaExport工具, 
展示SQL脚本。你使用这个工具把要完成的模式生成普通的SQL脚本。 
当然,此类操作你不想做为构建过程的一部分去做,如果使用Maven,例如,你使用Hibernate3-maven-plugin自动生成数据库架构。关键部分如示例13所示,当然你可以设置drop和export为false,这样就相当于没有更新数据库资料。 
示例13: 
<plugin> 
                <groupId>org.codehaus.mojo</groupId> 
                <artifactId>hibernate3-maven-plugin</artifactId> 
                <version>2.1</version> 
                <executions> 
                    <execution> 
                        <phase>process-classes</phase> 
                        <goals> 
                            <goal>hbm2ddl</goal> 
                        </goals> 
                    </execution> 
                </executions> 
                <configuration> 
                    <components> 
                        <component> 
                            <name>hbm2ddl</name> 
                            <implementation>annotationconfiguration</implementation> 
                        </component> 
                        <component> 
                            <name>hbmdoc</name> 
                        </component> 
                    </components> 
                    <componentProperties> 
                        <configurationfile>/target/classes/hibernate.cfg.xml</configurationfile> 
                        <outputfilename>schema.ddl</outputfilename> 
                        <namingstrategy>mycompany.myapp.IRDNamingStrategy</namingstrategy> 
                        <drop>false</drop> 
                        <create>true</create> 
                        <export>false</export> 
                        <format>true</format> 
                    </componentProperties> 
                </configuration> 
            </plugin> 
这样会生成SQL脚本,可以拿给DBA们看了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值