今天再次纠结于数据库设计是否要预留备用字段,当定制人员跟我说java以后扩展字段会很麻烦时,需要修改表结构后,还要domain下相关类及映射文件,我犹豫了。不过后来看到Hibernate正向工程可以自动生成表结构我坚定了不预留备用字段的想法。备用字段,它们的作用是什么呢?就是以防万一,防备可能的情况。
这似乎可以叫做防患于未然,等到时候需要的时候,就不需要在表中增加新的字段了,而且这样做的话,一个表的数据应该会被存储在相邻的物理空间中,这对于性能也是有好处的。
另外的原因就是,在古老的数据库中,如果改变数据库的定义(包括增加字段、改变字段的类型、删除字段等等),那么其中所有的数据就会丢失,所以这项工作非常麻烦,我们需要先建立临时表,将数据备份出来,然后创建新表,将数据导入其中,最后再删除原来的表。
问题所在:
这样的做法对于项目会导致很多问题,而且原先想要解决的问题并不一定能够解决,不信的话,请往下看。
问题一:增加大量备用字段,必定会浪费很多空间,尽管其中可能都没有具体的数据,但是仅仅是空字段也会占据一定的空间的。
问题二:由于命名的特点,如果没有完善的文档管理流程,用不了多久(可能也就是两三年),就没有人能够说清楚到底哪个字段代表的是什么意义了。就算有文档管理,这些管理工作也会比较麻烦,而且在每次使用的时候都需要申请,还有可能会出现冲突的情况。
问题三:增加了这些备用字段就真的会够用吗?不一定,因为我们只是每个类型的字段留出几个备用,如果数量超过,或者要使用特殊的、不常用的类型的时候,还是需要增加新的字段。比方说在上述的Person表中,我们要存储照片,那么可能就要增加一个blob类型的photo字段,这在初期设计的时候可不一定会留出这样的备用字段。而且如果没有完善的管理,谁又能说清楚倒底哪个字段已经被使用,哪个字段还可以使用呢?到时候还不是要增加新的字段。
解决方案:
其实上面的这种设计方式就是一种"过度设计",我们应该做的就是"按需设计",在经过详细有效的分析之后,在数据表中只放置必要的字段,而不要留出大量的备用字段。
当需要增加相关的信息的时候,就要具体情况具体分析:
如果数量很少,而且信息的性质与原表密切相关,那么就可以直接在原表上增加字段,并将相关的数据更新进去。
如果数量较大,或者并非是原表对象至关重要的属性,那么就可以新增一个表,然后通过键值连接起来。
对于表的数据的存储位置所导致的性能问题,我们可以通过在特定时间对数据库的数据进行重组来解决,而这项工作对于长期运行的数据库来说,也是需要定期进行的。
今天再次发现findbugs的功能真的很好很强大,代码审核时帮助我发现了同事好几个代码漏洞,发现现在代码审核经常出现的问题有以下几类:
- 代码不规范,长度超过120个字符,空格不对等
- 没有做空值判断
- 不同类型的值判断,尤其是int与Integer之类的
- 注释不规范等问题
hibernate能动态生成数据库表
如果你是单独使用hibernate的,请在hibernate.cfg.xml里面的sessionfactory下配置<property name="hbm2ddl.auto"></property>这个属性如果你是使用SSH组合框架的,而且由SPRING管理sessionfactory的,请在applicationContext.xml里面配置<property name="hibernateProperties"><props><prop key="hibernate.dialect">数据库方言</prop><prop key="hibernate.show_sql">是否打印SQL</prop><prop key="hibernate.hbm2ddl.auto">建表语句(参考值:validate | update | create | create-drop ,一般用update)</prop></props></property>
hibenate.hbm2ddl.auto属性详解
hibernate 配置属性中,hibernate.hbm2ddl.auto可以帮助你实现正向工程,即由java代码生成数据库脚本,进而生成具体的表结构.
&在hibernate.cfg.xml中:
Java代码 复制代码
1. <property name="hibernate.hbm2ddl.auto">
2. </property>
<property name="hibernate.hbm2ddl.auto">
</property>
它包含4个属性:
* create : 会根据你的model类来生成表,但是每次运行都会删除上一次的表,重新生成表,哪怕2次没有任何改变
* create-drop : 根据model类生成表,但是sessionFactory一关闭,表就自动删除
* update : 最常用的属性,也根据model类生成表,即使表结构改变了,表中的行仍然存在,不会删除以前的行
* validate : 只会和数据库中的表进行比较,不会创建新表,但是会插入新值
在hibernate中,如果在hibernate.cfg.xml文件中,将hibernate.hbm2ddl.auto设置为update(或者cretae-drop)也可以,如下
<property name="hibernate.hbm2ddl.auto">update</property>
则在运行应用程序时(第一次),会自动建立起表的结构(前提是先建立好数据库)。要注意的是,
当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会
如果是spring配置文件中配置则为
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.Oracle9Dialect
</prop>
<prop key="hibernate.connection.autocommit">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
hibernate使用了jdbc默认的databasemeta来寻找相应表数据信息,当使用默认的配置时,由于某种原因(并不是每次都能发生,取决于数据库本身以及相应的驱动)。当使用当前用户连接到数据库时,使用databasemeta寻找数据库表信息时,会查询出其它用户的数据表信息(即使当前用户没有相应的权限)。
解决此问题的方法很简单,只需要在hibernate.cfg.xml中配置一句:
1 <property name="default_schema">当前连接用户</property>
这样,使用databasemeta时,就会强制性地在当前用户空间中寻找数据库信息了,这样就能正确的创建出表结构了。