使用JPA指定索引(非唯一键)

问题描述 投票:78回答:11

如何使用JPA注释定义一个字段,例如email具有索引。我们在email上需要一个非唯一的密钥,因为每天在这个字段上有数百万个查询,没有密钥它有点慢。

@Entity
@Table(name="person", 
       uniqueConstraints=@UniqueConstraint(columnNames={"code", "uid"}))
public class Person {
    // Unique on code and uid
    public String code;
    public String uid;

    public String username;
    public String name;
    public String email;
}

我已经看到了一个特定于hibernate的注释,但我正在尝试避免供应商特定的解决方案,因为我们仍然在决定hibernate和datanucleus之间。

更新:

从JPA 2.1开始,您可以这样做。见:The annotation @Index is disallowed for this location

java hibernate orm jpa datanucleus
11个回答
3
投票

据我所知,没有一种跨JPA-Provider方式来指定索引。但是,您始终可以直接在数据库中手动创建它们,大多数数据库将在查询计划期间自动选择它们。


0
投票

使用JPA注释不可能做到这一点。这是有道理的:在UniqueConstraint明确定义业务规则的地方,索引只是一种使搜索更快的方法。所以这应该由DBA完成。


0
投票

此解决方案适用于EclipseLink 2.5,它可以工作(测试):

@Table(indexes = {@Index(columnList="mycol1"), @Index(columnList="mycol2")})
@Entity
public class myclass implements Serializable{
      private String mycol1;
      private String mycol2;
}

这假设上升顺序。


169
投票

使用JPA 2.1,您应该能够做到这一点。

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Index;
import javax.persistence.Table;

@Entity
@Table(name = "region",
       indexes = {@Index(name = "my_index_name",  columnList="iso_code", unique = true),
                  @Index(name = "my_index_name2", columnList="name",     unique = false)})
public class Region{

    @Column(name = "iso_code", nullable = false)
    private String isoCode;

    @Column(name = "name", nullable = false)
    private String name;

} 

更新:如果您需要使用两个或更多列创建和索引,则可以使用逗号。例如:

@Entity
@Table(name    = "company__activity", 
       indexes = {@Index(name = "i_company_activity", columnList = "activity_id,company_id")})
public class CompanyActivity{

28
投票

JPA 2.1(最后)增加了对索引和外键的支持!有关详细信息,请参阅this blog。 JPA 2.1是Java EE 7的一部分,它已经出来了。

如果您喜欢生活在边缘,您可以从他们的maven repository获取eclipselink的最新快照(groupId:org.eclipse.persistence,artifactId:eclipselink,version:2.5.0-SNAPSHOT)。对于JPA注释(一旦它们支持2.1,它应该适用于任何提供者)使用artifactID:javax.persistence,version:2.1.0-SNAPSHOT。

我正在将它用于一个项目,该项目在发布之后才会完成,我没有注意到任何可怕的问题(虽然我没有做任何太复杂的事情)。

更新(2013年9月26日):现在中央(主)存储库中提供了eclipselink的发布和发布候选版本,因此您不再需要在Maven项目中添加eclipselink存储库。最新发布的版本是2.5.0,但也存在2.5.1-RC3。由于2.5.0版本的问题,我会尽快切换到2.5.1(modelgen的东西不起作用)。


28
投票

A unique hand-picked collection of Index annotations

= Specifications =

= ORM Frameworks =

= ORM for Android =

= Other (difficult to categorize) =

  • Realm - 适用于iOS / Android的替代数据库:注释io.realm.annotations.Index;
  • Empire-db - 一个基于JDBC的轻量级但功能强大的关系数据库抽象层。它没有通过注释的模式定义;
  • Kotlin NoSQL (GitHub) - 用于处理NoSQL数据库(PoC)的反应式和类型安全的DSL:???
  • Slick - Scala的反应性功能关系映射。它没有通过注释的架构定义。

只去其中一个。


6
投票

在JPA 2.1中,您需要执行以下操作

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;

@Entity(name="TEST_PERSON")
@Table(
    name="TEST_PERSON", 
    indexes = {
       @Index(name = "PERSON_INDX_0", columnList = "age"),
       @Index(name = "PERSON_INDX_1", columnList = "fName"),
       @Index(name = "PERSON_INDX_1", columnList = "sName")  })
public class TestPerson {

    @Column(name = "age", nullable = false)
    private int age;

    @Column(name = "fName", nullable = false)
    private String firstName;

    @Column(name = "sName", nullable = false)
    private String secondName;

    @Id
    private long id;

    public TestPerson() {
    }
}

在上面的示例中,表TEST_PERSON将具有3个索引:

  • 主键ID上的唯一索引
  • 年龄指数
  • FNAME,SNAME上的复合索引

注1:通过使用两个具有相同名称的@Index注释获得复合索引

注意2:您在columnList中指定列名而不是fieldName


5
投票

我真的希望能够以标准化的方式指定数据库索引,但遗憾的是,这不是JPA规范的一部分(可能因为JPA规范不要求DDL生成支持,这是一种路障这样的功能)。

因此,您必须依赖提供商特定的扩展。 Hibernate,OpenJPA和EclipseLink显然提供了这样的扩展。我无法确认DataNucleus,但由于索引定义是JDO的一部分,我想它确实如此。

我真的希望索引支持在下一版本的规范中得到标准化,因此不同意其他答案,我认为没有任何理由不在JPA中包含这样的东西(特别是因为数据库并不总是在你的控制之下)获得最佳的DDL生成支持。

顺便说一句,我建议下载JPA 2.0规范。


2
投票

EclipseLink提供了一个注释(例如@Index)来定义列的索引。有一个example的使用。部分示例包括......

firstName和lastName字段是一起索引的,也是单独索引的。

@Entity
@Index(name="EMP_NAME_INDEX", columnNames={"F_NAME","L_NAME"})  // Columns indexed together
public class Employee{
    @Id
    private long id;

    @Index                      // F_NAME column indexed
    @Column(name="F_NAME")
    private String firstName;

    @Index                      // L_NAME column indexed
    @Column(name="L_NAME")
    private String lastName;
    ...
}

1
投票

OpenJPA允许您指定非标准注释以定义属性的索引。

详情是here


1
投票

总结其他答案:

我会选择其中一个。无论如何它都将带有JPA 2.1,并且在你真的想要切换你的JPA提供者的情况下不应该太难改变。

© www.soinside.com 2019 - 2024. All rights reserved.