2012-12-27 34 views
0

我正在試驗使用JPA生成索引。我已經知道JPA規範本身並不考慮生成索引的標準方法,但(某些)提供程序支持此功能。我正在測試新出生的Batoo(http://batoo.jp/),它對Hibernate和我對一個意外(對我的公司)行爲感到好奇。我們有2個類,首先定義沒有任何索引,並且我們在第二次定義兩個索引。當我們查看生成的表時,我們發現沒有實際創建索引。然後我們立即製作了這兩個類的精確副本,並將這些索引反映在數據庫中。這裏是重要的配置和類文件。
JPA-beans.xml文件(對Hibernate)使用JPA創建MySQL索引(Hibernate和Batoo)

<?xml version="1.0" encoding="UTF-8"?> 
<beans:beans profile="hibernate" xmlns:beans="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://www.springframework.org/schema/data/jpa" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/data/jpa 
    http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> 

    <beans:import resource="classpath:spring/jpa-common.xml"/> 

    <beans:bean id="entityManagerFactory" 
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <beans:property name="dataSource" ref="dataSource" /> 
     <beans:property name="jpaVendorAdapter"> 
      <beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
       <beans:property name="database" value="MYSQL" /> 
       <beans:property name="showSql" value="true" /> 
      </beans:bean> 
     </beans:property> 
     <beans:property name="persistenceUnitName" value="jpa.sample" /> 
     <beans:property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/> 
     <beans:property name="jpaProperties"> 
      <beans:props> 
       <beans:prop key="hibernate.enable_lazy_load_no_trans">true</beans:prop> 
       <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop> 
      </beans:props> 
     </beans:property> 
    </beans:bean> 

    <beans:bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> 
     <beans:property name="entityManagerFactory" ref="entityManagerFactory" /> 
     <beans:property name="jpaDialect"> 
      <beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" /> 
     </beans:property> 
    </beans:bean> 

</beans:beans> 

對於Batoo,我們只需將jpaVendorAdapter改變我們的自定義一個與jpaProperties映射,以使用由Batoo提供的特性。

的註解的Java類:
地址(在@Table註釋的uniqueConstraints是當表上的數據庫已經存在添加)和CopyOfAddress(在註解@Table立即那裏uniqueConstraints)。省略了setter和getter。

@Entity 
@Table(uniqueConstraints={ 
    @UniqueConstraint(name="uniqueAddress", columnNames={ 
     "zipCode", "street", "number", "city", "country" 
    }) 
}) 
public class Address extends BaseEntity 
{ 
    private String zipCode; 
    private String street; 
    private String number; 
    private String city; 
    private String country; 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    Long id; 

    @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}) 
    private User user; 
    ... 
} 

用戶CopyOfUser

@Entity 
public class User extends BaseEntity 
{ 
    @Column(unique=true) 
    private String username; 

    private String fullName; 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    private Long id; 
    ... 
} 


我們預計該數據庫中創建的表是相同的,但在這裏使用mysqldump獲得轉儲(只是有關創建表的語句) :

CREATE TABLE `Address` (
    `zipCode` varchar(255) DEFAULT NULL, 
    `street` varchar(255) DEFAULT NULL, 
    `user_id` bigint(20) DEFAULT NULL, 
    `number` varchar(255) DEFAULT NULL, 
    `country` varchar(255) DEFAULT NULL, 
    `city` varchar(255) DEFAULT NULL, 
    `id` bigint(20) DEFAULT NULL, 
    KEY `FK_A2CD7CE3` (`user_id`), 
    CONSTRAINT `FK_A2CD7CE3` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

CREATE TABLE `CopyOfAddress` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `city` varchar(255) DEFAULT NULL, 
    `country` varchar(255) DEFAULT NULL, 
    `number` varchar(255) DEFAULT NULL, 
    `street` varchar(255) DEFAULT NULL, 
    `zipCode` varchar(255) DEFAULT NULL, 
    `user_id` bigint(20) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `zipCode` (`zipCode`,`street`,`number`,`city`,`country`), 
    KEY `FKA0BC6A08E9A4D67F` (`user_id`), 
    CONSTRAINT `FKA0BC6A08E9A4D67F` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

CREATE TABLE `User` (
    `id` bigint(20) NOT NULL DEFAULT '0', 
    `username` varchar(255) DEFAULT NULL, 
    `fullName` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

DROP TABLE IF EXISTS `CopyOfUser`; 

CREATE TABLE `CopyOfUser` (
    `id` bigint(20) NOT NULL DEFAULT '0', 
    `username` varchar(255) DEFAULT NULL, 
    `fullName` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `username` (`username`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

正如你所看到的,在User和Address中都沒有索引被創建,而它們是完全相同的。有誰知道爲什麼?而且,作爲一個側面問題,是否有人知道爲什麼我們爲CopyOfAddress中的索引提供的名稱不被考慮?

編輯
如果它可以幫助,我可以加我使用Hibernate的4.1.7.Final和Batoo 2.0.1.0-RTM。

+0

我的猜測是,當表已經創建並且索引必須被添加時,使用JPA提供者(至少我們嘗試過的兩種)是不可能的,因爲他們不知道如何處理現有數據,所以(也許)索引創建功能僅在創建時可用,而不能在表格的變更中使用...這可能嗎? – ThanksForAllTheFish

回答

0

我使用一些日誌深入瞭解更多細節,並且發現Hibernate(不知道Batoo)僅在創建表時創建索引,而僅在僅用於(且僅用於)添加新列(即使現有數據庫表不包含任何數據,也不刪除現有列)。在地方

DEBUG [tool.hbm2ddl.SchemaUpdate] create table CopyOfCopyOfAddress (id bigint not null auto_increment, city varchar(255), country varchar(255), number varchar(255), street varchar(255), zipCode varchar(255), user_id bigint, primary key (id), unique (zipCode, street, number, city, country)) 
DEBUG [tool.hbm2ddl.SchemaUpdate] alter table CopyOfCopyOfAddress add index FK50EC293CE9A4D67F (user_id), add constraint FK50EC293CE9A4D67F foreign key (user_id) references User (id) 


添加一個新的列到現有的表,其中唯一約束設置成

從頭開始創建一個新的表,具有唯一約束:這裏是一些日誌證明了這java文件,但不進DB

DEBUG [tool.hbm2ddl.SchemaUpdate] alter table Address add column zipCode2 varchar(255) 


在第二種情況下,我我期待看到像alter table Address add unique(zipCode, street, number, city, country);(記住地址。java),因此顯而易見,Hibernate不會爲現有表添加唯一的約束(至少使用標準的JPA註釋)!
如果我沒有被證明是錯誤的,我很快就會接受這個答案,因爲我不知道還有什麼要測試的東西,而且我沒有找到任何文檔。