Hibernate不使用Firebird序列,而是尝试使用表

时间:2017-04-26 14:04:23

标签: java hibernate firebird

我正在尝试使用

将新用户从休眠状态插入到Firebird数据库中
Session session = factory.openSession();

UserDetail user = new UserDetail();
user.setName("Mark");
user.setPassword("1234567");
user.setUserType(1L);

session.beginTransaction();
try {
    session.persist(user);
    session.getTransaction().commit();
} catch (Exception  e) {
    session.getTransaction().rollback();
} finally {
    session.close();
}

我的实体是

@Entity
@Table(name = "USER_DETAIL")
public class UserDetail
{
    @Id
    @Column(name = "ID", nullable = false)
    @SequenceGenerator(name = "gen", sequenceName = "GEN_USER_DETAIL_ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "gen")
    private Long id;

    @Column(name = "TYPE_ID")
    @NotNull
    private Long userType;

    @Column(name = "NAME")
    @NotNull
    @Size(min = UserDetailConstraint.MIN_USER_NAME, max = UserDetailConstraint.MAX_USER_NAME)
    private String name;

    @Column(name = "HASHED_PASSWORD")
    @NotNull
    @Size(min = UserDetailConstraint.MIN_PASSWORD, max = UserDetailConstraint.MAX_PASSWORD)
    private String password;

    public Long getId() { return id;  }
    public void setId(Long id) { this.id = id; }

    public Long getUserType() { return userType; }
    public void setUserType(Long userType) { this.userType = userType; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }


    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}

但是当hibernate尝试通过生成器检索新的id时,它使用

select next_val as id_val from GEN_USER_DETAIL_ID with lock

但是GEN_USER_DETAIL_ID不是表,它是一个序列。

因此程序崩溃并出现错误

WARN: HHH10001002: Using Hibernate built-in connection pool (not for 

production use!)
апр 26, 2017 5:19:06 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [org.firebirdsql.jdbc.FBDriver] at URL [jdbc:firebirdsql://localhost:3050/warehouse]
апр 26, 2017 5:19:06 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {user=SYSDBA, password=****}
апр 26, 2017 5:19:06 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
апр 26, 2017 5:19:06 PM org.hibernate.engine.jdbc.connections.internal.PooledConnections <init>
INFO: HHH000115: Hibernate connection pool size: 5 (min=1)
апр 26, 2017 5:19:06 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.FirebirdDialect
апр 26, 2017 5:19:06 PM org.hibernate.id.enhanced.SequenceStyleGenerator configure
INFO: HHH000107: Forcing table use for sequence-style generator due to pooled optimizer selection where db does not support pooled sequences
апр 26, 2017 5:19:07 PM org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 4.3.2.Final
Hibernate: select next_val as id_val from GEN_USER_DETAIL_ID with lock
апр 26, 2017 5:19:07 PM org.hibernate.id.enhanced.TableStructure$1$1 execute
ERROR: could not read a hi value
org.firebirdsql.jdbc.FBSQLException: GDS Exception. 335544569. Dynamic SQL Error
SQL error code = -204
Table unknown
GEN_USER_DETAIL_ID
At line 1, column 51

当我使用xml映射而不是注释时,一切正常。

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

我找到了一种使用火鸟发生器的方法。需要这个。

@Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "gen")
    @GenericGenerator(name = "gen", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
            parameters = {@org.hibernate.annotations.Parameter(name = "sequence_name", value = "GEN_USER_DETAIL_ID")
            })

答案 1 :(得分:1)

@SequenceGenerator默认分配大小为50,这需要池化序列。 Firebird不支持池化序列(技术上支持它,但不支持Hibernate所需的方式)。除1之外的分配大小会触发Hibernate来使用基于表的策略。

这在日志中也有说明:

  

апр26,20175:19:06 PM org.hibernate.id.enhanced.SequenceStyleGenerator配置
  信息:HHH000107:由于汇总优化器选择而强制表用于序列式生成器,其中db不支持池化序列

由于您没有该表,因此会出现错误。

有几种解决方案:

  1. 将分配大小更改为1

    @SequenceGenerator(name = "gen", 
            sequenceName = "GEN_USER_DETAIL_ID", 
            allocationSize = 1)
    
  2. 改为创建必要的表格并用1行填充:

    drop sequence GEN_USER_DETAIL_ID;
    commit;
    create table GEN_USER_DETAIL_ID (
        next_val INTEGER NOT NULL
    );
    commit;
    insert into GEN_USER_DETAIL_ID (next_val) values (1);
    commit;
    
  3. 创建一个触发器来分配id(或者,如果您使用的是Firebird 3,您也可以将该列声明为GENERATED BY DEFAULT AS IDENTITY

    set term #;
    create trigger user_detail_bi before insert on user_detail
    as
    begin
       new.id = next value for GEN_USER_DETAIL_ID;
    end#
    set term ;#
    commit;
    

    并将@GeneratedValue更改为IDENTITY

    @Id
    @Column(name = "ID", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
  4. 选项2和3可能更适合性能。