插入后选择Hibernate

时间:2017-12-20 21:31:06

标签: mysql spring hibernate spring-data

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

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

  1. 我创建了一个sequences表,它使用了一个自动增量字段(用作我的表格的id')。
  2. 创建了一个函数sequences_nextvalue(),它插入sequences表并返回新的自动增加的id。
  3. 然后我在每个表上创建触发器,在插入之前触发,并用调用sequences_nextvalue()的结果替换id字段。
  4. 因此,在插入新行时,此功能正常。我在所有表格中获得了独特的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列放在该类中,并将@EntityInheritanceType.TABLE_PER_CLASS一起使用。我还将id初始化为-1,因为需要id来从我的spring crud存储库调用save()

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

    是否可以强制Hibnerate在插入后重新选择实体,以便在您不使用save()时获取新ID?

    非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

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

我没有创建MySQL TRIGGER来替换id上的INSERT,而是创建了一个执行IdentifierGenerator的{​​{1}}的Hibernate 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 ^;