【问题标题】:Hibernate select after insertion插入后休眠选择
【发布时间】:2018-06-03 12:30:46
【问题描述】:

我在将新行插入我的 MySQL 数据库时遇到问题。我正在使用 Spring Boot 和 Spring Boot Data JPA。

由于 MySQL 不支持序列,我决定尝试制作自己的序列生成器表。这基本上就是我所做的。

  1. 我创建了一个 sequences 表,该表使用自动增量字段(用作我的表的 ID)。
  2. 创建了一个函数 sequences_nextvalue(),它插入到 sequences 表中并返回新的自动递增 id。
  3. 然后,我在每个表上创建了在插入之前触发的触发器,并将 id 字段替换为调用 sequences_nextvalue() 的结果。

所以在插入新行时它工作正常。我在所有表中都获得了唯一的 ID。我遇到的问题与我的 JPA 实体有关。

@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractBaseClass {
  @Id
  private Integer id = -1;
  ...
}

@Entity
public class ConcreteClass1 extends AbstractBaseClass {
  ...
}


@Entity
public class ConcreteClass2 extends AbstractBaseClass {
  ...
}

我希望能够从抽象基类进行查询,因此我将@Id 列放在该类中,并将@Entity 与InheritanceType.TABLE_PER_CLASS 一起使用。我还将 id 初始化为 -1,因为需要一个 id 才能从我的 spring crud 存储库中调用 save()。

在调用我的 Spring 数据 CrudRepository 的 save() 函数后,id 的 -1 正确地被 MySQL 触发器替换,但 save() 返回的结果实体不会返回新的 id,而是而是保留 -1。查看 SQL 日志后,插入后不会调用 select 语句来获取新 id,而是返回原始实体。

当你不使用@GeneratedValue时,是否可以强制Hibnerate在插入后重新选择实体以获取新的id?

非常感谢任何帮助。

【问题讨论】:

  • AUTO_INCREMENT 的问题在于它的范围是这样的,因此每个表都有自己的AUTO_INCREMENT 字段,允许重叠 id。我想在多个表中拥有唯一的 id,这意味着如果我在 SOME_TABLE 中的 id 为 1,ANOTHER_TABLE 中的 id 不会为 1。所以基本上我想要多个表共享和AUTO_INCREMENT 字段。
  • 我已经有这个工作但是因为我没有使用@GeneratedValue,Hibernate 没有执行SELECT 它通常在INSERT 之后执行所以我没有得到新生成的 id save() 上返回的实体。不过,ID 已正确存储在数据库中。

标签: mysql spring hibernate spring-data


【解决方案1】:

只是想提供有关此问题的最新信息。这是我的解决方案。

我没有创建 MySQL TRIGGER 来替换 INSERT 上的 id,而是创建了一个 Hibernate IdentifierGenerator,它执行 CallableStatement 来获取并返回一个新的 id。

我的抽象基类现在看起来像这样。

@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractBaseClass {

  @Id
  @GenericGenerator(name="MyIdGenerator", strategy="com.sample.model.CustomIdGenerator" )
    @GeneratedValue(generator="MyIdGenerator" )
  private Integer id;
  ...

}

我的生成器看起来像这样。

public class CustomIdGenerator implements IdentifierGenerator {

    private Logger log = LoggerFactory.getLogger(CustomIdGenerator.class);
    private static final String QUERY = "{? = call sequence_nextvalue()}";

    @Override
    public Serializable generate(SessionImplementor session, Object object) throws HibernateException {

        Integer id = null;
        try {
            Connection connection = session.connection();
            CallableStatement statement = connection.prepareCall(QUERY);
            statement.registerOutParameter(1, java.sql.Types.INTEGER);
            statement.execute();
            id = statement.getInt(1);
        } catch(SQLException e) {
            log.error("Error getting id", e);
            throw new HibernateException(e);
        }
        return id;
    }

}

仅供参考

sequences 表。

CREATE TABLE sequences (
  id INT AUTO_INCREMENT PRIMARY KEY,
  thread_id INT NOT NULL,
  created DATETIME DEFAULT CURRENT_TIMESTAMP
) ^;

sequence_nextvalue 函数

CREATE FUNCTION sequence_nextvalue()
RETURNS INTEGER
NOT DETERMINISTIC
MODIFIES SQL DATA
BEGIN
  DECLARE nextvalue INTEGER;
  INSERT INTO sequences (thread_id) VALUE (CONNECTION_ID());
  SELECT id FROM sequence_values ORDER BY created DESC LIMIT 1 INTO nextvalue;
  RETURN nextvalue;
END ^;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-19
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多