У меня возникла проблема с вставкой новых строк в мою базу данных MySQL. Я использую Spring Boot с Spring Boot Data JPA.
Поскольку MySQL не поддерживает последовательности, я решил попробовать создать собственную таблицу генератора последовательности. Это в основном то, что я сделал.
sequences
которая использует поле автоматического увеличения (используется как мой идентификатор для моих таблиц).sequences_nextvalue()
которая вставляет в таблицу sequences
и возвращает новый автоматически увеличиваемый id.sequences_nextvalue()
.Так что это прекрасно работает при вставке новых строк. Я получаю уникальные идентификаторы во всех таблицах. Проблема, с которой я столкнулась, связана с моими судами 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
. Я также инициализировал идентификатор -1, так как идентификатор требуется вызвать save()
из моего репозитория Spring Crud.
После вызова функции save()
моих данных Spring CrudRepository
значение -1 для id
должным образом заменяется триггером MySQL, но результирующий объект, возвращаемый функцией save()
, не возвращается с новым идентификатором, но вместо этого сохраняет -1, После просмотра журналов SQL оператор select не вызывается после вставки, чтобы получить новый идентификатор, но вместо этого возвращается исходный объект.
Можно ли заставить Hibnerate повторно выбрать объект после вставки, чтобы получить новый идентификатор, когда вы не используете @GeneratedValue
?
Любая помощь приветствуется.
Просто хочу предоставить обновление по этому вопросу. Вот мое решение.
Вместо того, чтобы создавать MySQL TRIGGER
для замены id
на INSERT
, я создал Hibernate IdentifierGenerator
который выполняет CallableStatement
для получения и возврата нового идентификатора.
Теперь мой абстрактный базовый класс выглядит следующим образом.
@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 ^;