当前位置: 首页 > 知识库问答 >
问题:

批插入在使用Spring Boot、hibernate和mysql时工作不正常

伯逸明
2023-03-14

我有一个非常恼人的问题,我已经在网上阅读了所有现有的文档,并阅读了所有与此主题相关的问题和答案,但根本无法使其发挥作用!

我真的很绝望,我不知道我错过了什么,所以我会努力给你我所拥有的一切。基本上,我试图做的是用一个查询保存大量数据,而不是每个对象的多个查询。你可以怀疑我正在使用Spring Boot, Hibernate和MySql。

因此,根据我读到的与“使用mysql hibernate进行批插入”相关的内容,到目前为止我学到的基本事实如下:

  1. Mysql不支持序列ID,所以我不能使用它,就像我可以将它用于PostgreSql一样

这就是我到目前为止所拥有的:

我添加的应用程序属性:

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

基本上,这应该会显示在DB上执行的查询,在那里我可以看到每个person对象都有一条insert语句。

基本上,这个查询的结果是:

SELECT
    *
FROM
    mysql.general_log;

在那里我可以清楚地看到,我有多个insert语句,每个对象(人)执行一个查询。

编辑: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)]

我有很多这样的记录。

提前感谢您的帮助!

共有1个答案

景嘉实
2023-03-14

只是为了在有人需要时给出答案:

长话短说,我不能让MySqlHibernate批次处理作业,为了测试,我实际上能够让它与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)
    }
}
 类似资料:
  • 我正在使用hibernate jpa执行批处理更新。 更新:我得到了解决方案:问题是我正在刷新已经刷新的事务,因此它没有给我任何事务正在进行中的错误以及我上面发布的错误,所以我只是删除了`getem().flush();和getEm().clear();从finally块开始工作:)

  • 我很难让Hibernate在MySQL上执行大容量插入。 我有要排序的主键生成类型,下面是我的dao.xml 这使得每次都可以执行单个查询。我也相应地刷新和清除实体管理器。 技术堆栈:Spring 4,Hibernate 5.2。 编辑1:我也浏览了下面的链接,但没有运气 https://vladmihalcea.com/how-to-batch-insert-and-update-stateme

  • 我需要在我的MySQL数据库中进行批量插入(近10000个)。我正在使用JPA/Hibernate和spring Boot。我从hibernate文档中读到了在hibernate中执行大容量插入/更新,我认为我的代码不能正常工作,因为它顺序地插入hibernate查询,而不是在批处理插入中执行它们。下面是我的代码。我是不是漏掉了什么? 这是我的数据源配置。 我是不是漏掉了什么? 请帮帮忙。

  • 我试图使用php/html表单将数据输入到mysql数据库中,但它不起作用,我不知道为什么。该记录没有插入,我只得到一个空白页后,我提交了表单。 谢谢,尤金妮 这是我的databaseenter图像描述 这是html表单: 这是php代码:

  • 我是javafx的新手,所以请原谅我的愚蠢错误,我使用javafx创建了一个注册fxml,但是当我试图存储数据时,它总是会把它扔到我的modelcontroller的catch块中,在那里我有一个sql的insert查询 这是我的modelcontroller将我的注册数据插入数据库 它总是抛出modelContoller中的catch块,我通过调试器检查过它

  • 我想在交叉表中插入大量的实体。为此,我想启用Hibernate的批处理插入选项,这样每次插入将不是添加1行,而是一次添加20或50行。 我正在尝试重现Hibernate教程的结果。我创建了一个测试函数,它将尝试插入30个客户,就像在示例中一样: Customer类没有生成的ID。 在收到Vlad Mihalcea的回答后,我意识到是的,事实上批处理语句是有效的,至少在hibernate和jdbc级