我有一个非常烦人的问题,我已经在线阅读了所有现有文档,并阅读了与该主题相关的所有 stackoverflow 问题和答案,但根本无法使其正常工作!
我真的很绝望,我不知道我错过了什么,所以我会尽力给你我迄今为止所拥有的一切。基本上我想做的是通过一个查询来保存大量数据,而不是为每个对象进行多个查询。正如您可能怀疑的那样,我正在使用 Spring Boot、Hibernate 和 MySql。
接下来是我根据我所读到的与“使用 mysql + hibernate 批量插入”相关的内容所学到的基本事实:
- Mysql 不支持 Sequence ID,所以我不能使用它,就像我可以将它用于 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)
}
}
}
所以在这里你可以看到,我试图以几乎相同的方式使其工作,但当然这两种方式似乎都不起作用。
为了确认我实际上正在执行批量插入,我正在查看这个:
https://tableplus.com/blog/2018/10/how-to-show-queries-log-in-mysql.html
所以基本上应该向我显示正在数据库上执行的查询,并且我可以看到对于每个人对象我都有一个插入语句。
基本上这个查询的结果:
SELECT
*
FROM
mysql.general_log;
在那里我可以清楚地看到我有多个插入语句,每个对象(人)执行一个查询。
编辑: 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)]
我有多条这样的记录。
预先感谢您提供任何帮助!
最佳答案
只是为了在有人需要时给出答案:
长话短说,我无法使 MySql + hibernate 批处理工作,为了测试,我实际上能够使其与 PostgreSQL 一起工作。
但是无论如何,如果有人需要使用 MySql,可以使用 JDBC 批处理,并且代码或多或少非常简单:
private String INSERT_SQL_PARAMS = "INSERT INTO item_params(p_key, p_value, item_id) values (?,?,?)"
override fun saveParams(configParams: Set<ItemParam>) {
jdbcTemplate!!.batchUpdate(INSERT_SQL_PARAMS , configParams, 3000) { ps, argument ->
ps.setLong(1, argument.pKey)
ps.setString(2, argument.pValue)
ps.setString(3, argument.itemId)
}
}
关于mysql - 使用 spring boot、hibernate 和 mysql 批量插入无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59130342/