PageRenderTime 26ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/atlassian-hibernate5-extras/src/main/java/com/atlassian/hibernate/extras/ResetableHiLoGeneratorHelper.java

https://bitbucket.org/atlassian/atlassian-hibernate-extras
Java | 153 lines | 118 code | 22 blank | 13 comment | 17 complexity | 361687cd62b7f8f981c6394b8e9ddfa4 MD5 | raw file
Possible License(s): LGPL-2.1
  1. package com.atlassian.hibernate.extras;
  2. import org.hibernate.JDBCException;
  3. import org.hibernate.Session;
  4. import org.hibernate.SessionFactory;
  5. import org.hibernate.engine.spi.SessionFactoryImplementor;
  6. import org.hibernate.engine.spi.SessionImplementor;
  7. import org.hibernate.jdbc.AbstractReturningWork;
  8. import org.hibernate.jdbc.AbstractWork;
  9. import org.hibernate.metadata.ClassMetadata;
  10. import org.hibernate.persister.entity.EntityPersister;
  11. import org.hibernate.persister.entity.SingleTableEntityPersister;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14. import java.sql.Connection;
  15. import java.sql.ResultSet;
  16. import java.sql.SQLException;
  17. import java.sql.Statement;
  18. import java.util.List;
  19. import java.util.Map;
  20. /**
  21. * This class is used to set the hibernate_unique_key.next_hi value to the high bits of the highest id in the DB, +1
  22. * after an import (for now) to maintain state in the database.
  23. *
  24. * @since 6.1
  25. */
  26. @SuppressWarnings("unused")
  27. public class ResetableHiLoGeneratorHelper {
  28. public static final String HIBERNATE_UNIQUE_KEY_COLUMN = "next_hi";
  29. public static final String HIBERNATE_UNIQUE_KEY_TABLE = "hibernate_unique_key";
  30. private static final Logger log = LoggerFactory.getLogger(ResetableHiLoGeneratorHelper.class);
  31. private SessionFactory sessionFactory;
  32. /**
  33. * @return long the next hi value
  34. */
  35. public long getHiValue() throws SQLException {
  36. Session session = sessionFactory.getCurrentSession();
  37. try {
  38. return ((SessionImplementor) session).getTransactionCoordinator()
  39. .createIsolationDelegate()
  40. .delegateWork(new NextHiGetter(), true);
  41. } catch (JDBCException e) {
  42. log.error("Error finding maximum next_hi value", e.getSQLException());
  43. throw e.getSQLException();
  44. }
  45. }
  46. public void setNextHiValue(List<String> errors) {
  47. Session session = sessionFactory.getCurrentSession();
  48. ((SessionImplementor) session).getTransactionCoordinator()
  49. .createIsolationDelegate()
  50. .delegateWork(new NextHiSetter(errors, sessionFactory), true);
  51. }
  52. public void setSessionFactory(SessionFactory sessionFactory) {
  53. this.sessionFactory = sessionFactory;
  54. }
  55. private static class NextHiGetter extends AbstractReturningWork<Long> {
  56. private static final String SQL = "select " + HIBERNATE_UNIQUE_KEY_COLUMN + " from " + HIBERNATE_UNIQUE_KEY_TABLE;
  57. @Override
  58. public Long execute(Connection connection) throws SQLException {
  59. try (Statement statement = connection.createStatement();
  60. ResultSet resultSet = statement.executeQuery(SQL)) {
  61. if (resultSet.next()) {
  62. return resultSet.getLong(1); // might be null, but that's ok, will return 0;
  63. }
  64. }
  65. return 0L;
  66. }
  67. }
  68. private static class NextHiSetter extends AbstractWork {
  69. private final List<String> errors;
  70. private final SessionFactoryImplementor sessionFactory;
  71. private NextHiSetter(List<String> errors, SessionFactory sessionFactory) {
  72. this.errors = errors;
  73. this.sessionFactory = (SessionFactoryImplementor) sessionFactory;
  74. }
  75. @Override
  76. public void execute(Connection connection) {
  77. Map<String, ClassMetadata> metadataMap = sessionFactory.getAllClassMetadata();
  78. try (Statement statement = connection.createStatement()) {
  79. long maximumId = 0;
  80. int maxLo = 0;
  81. for (String className : metadataMap.keySet()) {
  82. EntityPersister persister = sessionFactory.getEntityPersister(className);
  83. if (persister instanceof SingleTableEntityPersister &&
  84. persister.getIdentifierGenerator() instanceof ResettableTableHiLoGenerator) {
  85. SingleTableEntityPersister entityPersister = (SingleTableEntityPersister) persister;
  86. ResettableTableHiLoGenerator generator = (ResettableTableHiLoGenerator) persister.getIdentifierGenerator();
  87. // TODO need to work out why we have this logic.
  88. if (maxLo == 0) {
  89. maxLo = generator.getMaxLo();
  90. } else if (maxLo != generator.getMaxLo()) {
  91. //throw new UpgradeException("One generator uses " + maxLo + " for maxLo, generator for " +
  92. // c.getName() + " uses " + generator.getMaxLo());
  93. errors.add("One generator uses " + maxLo + " for maxLo, generator for " +
  94. className + " uses " + generator.getMaxLo());
  95. }
  96. String[] idColumnNames = entityPersister.getIdentifierColumnNames();
  97. if (idColumnNames.length != 1) {
  98. errors.add("Expected a single ID column for " + className + " found " + idColumnNames.length);
  99. }
  100. String sql = "select max(" + idColumnNames[0] + ") from " + entityPersister.getTableName();
  101. try (ResultSet resultSet = statement.executeQuery(sql)) {
  102. if (resultSet.next()) {
  103. long value = resultSet.getLong(1); // might be null, but that's ok, will return 0;
  104. if (value > maximumId) {
  105. maximumId = value;
  106. }
  107. } else {
  108. errors.add("No maximum ID returned for " + className);
  109. }
  110. }
  111. }
  112. }
  113. setNextHi(statement, (int) (maximumId / (maxLo + 1)) + 1);
  114. } catch (Exception e) {
  115. log.error("Error finding maximum next_hi value", e);
  116. errors.add(e.getMessage());
  117. } finally {
  118. log.info("Completed database update: HiLoIdRepairUpgradeTask");
  119. }
  120. }
  121. private void setNextHi(Statement statement, int nextHi) throws SQLException {
  122. log.info("Setting new next_hi to " + nextHi);
  123. if (statement.executeUpdate("update " + HIBERNATE_UNIQUE_KEY_TABLE + " set " + HIBERNATE_UNIQUE_KEY_COLUMN + " = " + nextHi) == 0) {
  124. // no row, need to insert one
  125. if (statement.executeUpdate("insert into " + HIBERNATE_UNIQUE_KEY_TABLE + " values(" + nextHi + ")") == 0) {
  126. errors.add("failed to insert initial next_hi value");
  127. }
  128. }
  129. }
  130. }
  131. }