У меня есть одна очень раздражающая проблема, я прочитал всю существующую документацию онлайн и прочитал все вопросы и ответы по stackoverflow, связанные с этой темой, но просто не могу заставить это работать!
Я действительно в отчаянии и не знаю, чего мне не хватает, поэтому я постараюсь дать вам все, что у меня есть. По сути, я пытаюсь сохранить много данных одним запросом вместо нескольких запросов для каждого объекта. Как вы можете подозревать, я использую Spring Boot, Hibernate и MySql.
Итак, основные факты, которые я узнал на основе того, что я прочитал о «пакетной вставке с использованием mysql + hibernate», следующие:
- Mysql не поддерживает идентификатор последовательности, поэтому я не могу использовать его, как я мог бы использовать его для PostgreSql
- Hibernate не поддерживает пакетную вставку из коробки, есть пара свойств приложениячто нужно добавить
И вот что у меня есть:
Свойства приложения, которые я добавил:
spring.datasource.url=jdbc:mysql://localhost:32803/db?rewriteBatchedStatements=true
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.batch_versioned_data=true
spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.type=trace
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
@Entity
data class Person (
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Long?,
var firstName: String,
var lastName: String,
var country: String,
var org: Int
)
Что я хочу сохранитьмного людей одновременно, как вы можете видеть, я добавил размер пакета 50, если я правильно понял, это означает, что я буду делать одно попадание в базу данных на 50 человек при сохранении. (поправьте меня, если я ошибаюсь)
И в конце у меня есть репозиторий, где я выполняю эту пакетную вставку:
@Repository
class PersonRepositoryCustomImpl : PersonRepositoryCustom {
@PersistenceContext
private val entityManager: EntityManager? = null
@Transactional
override fun batchSave2(persons: Set<Person>) {
val session = entityManager!!.unwrap(Session::class.java)
persons.forEachIndexed { index, person ->
if ( index % 50 == 0 ) {
session!!.flush()
session.clear()
}
session!!.save(person)
}
session.close()
}
@Transactional
override fun <T : Person?> batchSave(entities: Collection<T>): Collection<T>? {
val savedEntities: MutableList<T> = ArrayList(entities.size)
var i = 0
for (t in entities) {
savedEntities.add(persistOrMerge(t))
i++
if (i % 50 == 0) { // Flush a batch of inserts and release memory.
entityManager!!.flush()
entityManager.clear()
}
}
return savedEntities
}
private fun <T : Configuration?> persistOrMerge(t: T): T {
return if (t!!.id == null) {
entityManager!!.persist(t)
t
} else {
entityManager!!.merge(t)
}
}
}
Так что здесь вы можете увидеть, что я пытался заставить это работатьна 2 почти одинаковых пути, но, конечно, оба они, кажется, не работают.
Чтобы подтвердить, что я фактически делаю пакетную вставку, я смотрю на это:
https://tableplus.com/blog/2018/10/how-to-show-queries-log-in-mysql.html
так что в основном это должно показать мне запросы, которые выполняются в БД, и там я вижу, что для каждого объекта person у меня есть один оператор вставки.

По сути, результат этого запроса:
SELECT
*
FROM
mysql.general_log;
И там я отчетливо вижу, что у меня есть несколько операторов вставки, которые выполняют один запрос на объект (персона).
Edit: https://blog.arnoldgalovics.com/configuring-a-datasource-proxy-in-spring-boot/
Я также реализовал прокси источника данных, который доказал мне, что я не делаю пакетную вставку:
Name:, Time:1, Success:True, Type:Prepared, Batch:False, QuerySize:1, BatchSize:0, Query:["insert into person(firstName, lastName, country, org) values (?, ?, ?, ?)"], Params:[(10,John,Johny,USA,ORG)]
У меня есть несколько записей, подобных этой.
Заранее спасибо за любую помощь!