0

我正在尝试使用 JPA 生成索引。我已经知道 JPA 规范本身并没有考虑生成索引的标准方法,但是(一些)提供程序支持此功能。我正在测试新出生的 Batoo (http://batoo.jp/) 和 Hibernate,我对意外的(对我的公司而言)行为感到好奇。我们有 2 个类,第一次定义没有任何索引,我们在其上定义了第二次索引。当我们查看生成的表时,我们发现实际上没有创建索引。然后我们制作了这两个类的精确副本,索引立即到位,这些索引反映在数据库中。这里重要的配置和类文件。jpa-beans.xml
(用于休眠)

<?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 是在 DB 上已经存在表时添加的)和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;
  ...
}


我们希望在 db 上创建的表是相同的,但这里使用 mysqldump 获得的转储(只是相关的 create table 语句):

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;

如您所见,在用户和地址中都没有创建索引,而它们在精确的副本中。有谁知道为什么?而且,作为一个附带问题,有谁知道为什么不考虑我们在 CopyOfAddress 中为索引提供的名称?

编辑
如果可能有帮助,我可以添加我正在使用 Hibernate 4.1.7.Final 和 Batoo 2.0.1.0-RTM。

4

1 回答 1

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);(记住 Address.java)这样的行,因此很明显 Hibernate 不会向现有表添加唯一约束(至少使用标准 JPA 注释)!
如果我没有被证明是错误的,我很快就会接受这个作为答案,因为我不知道还有什么要测试的,而且我没有找到任何文档。

于 2012-12-28T12:21:16.363 回答