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

如何使用JParepository进行大容量(多行)插入?

薛扬
2023-03-14

当从服务层调用我的JParepositorySaveAll方法时,使用一个长的列表 时,Hibernate的跟踪日志记录会显示每个实体发出的单个SQL语句。

我是否可以强制它进行大容量插入(即多行),而不需要手动摆弄entitymanger、事务等,甚至不需要原始SQL语句字符串?

start transaction
INSERT INTO table VALUES (1, 2)
end transaction
start transaction
INSERT INTO table VALUES (3, 4)
end transaction
start transaction
INSERT INTO table VALUES (5, 6)
end transaction

致:

start transaction
INSERT INTO table VALUES (1, 2)
INSERT INTO table VALUES (3, 4)
INSERT INTO table VALUES (5, 6)
end transaction

而是改为:

start transaction
INSERT INTO table VALUES (1, 2), (3, 4), (5, 6)
end transaction

在PROD中,我使用的是CockroachDB,性能上的差异是显著的。

package things

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.data.jpa.repository.JpaRepository
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.GeneratedValue

interface ThingRepository : JpaRepository<Thing, Long> {
}

@RestController
class ThingController(private val repository: ThingRepository) {
    @GetMapping("/test_trigger")
    fun trigger() {
        val things: MutableList<Thing> = mutableListOf()
        for (i in 3000..3013) {
            things.add(Thing(i))
        }
        repository.saveAll(things)
    }
}

@Entity
data class Thing (
    var value: Int,
    @Id
    @GeneratedValue
    var id: Long = -1
)

@SpringBootApplication
class Application {
}

fun main(args: Array<String>) {
    runApplication<Application>(*args)
}
jdbc.driverClassName = org.h2.Driver
jdbc.url = jdbc:h2:mem:db
jdbc.username = sa
jdbc.password = sa

hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto=create

spring.jpa.generate-ddl = true
spring.jpa.show-sql = true

spring.jpa.properties.hibernate.jdbc.batch_size = 10
spring.jpa.properties.hibernate.order_inserts = true
spring.jpa.properties.hibernate.order_updates = true
spring.jpa.properties.hibernate.jdbc.batch_versioned_data = true
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    val kotlinVersion = "1.2.30"
    id("org.springframework.boot") version "2.0.2.RELEASE"
    id("org.jetbrains.kotlin.jvm") version kotlinVersion
    id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion
    id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion
    id("io.spring.dependency-management") version "1.0.5.RELEASE"
}

version = "1.0.0-SNAPSHOT"

tasks.withType<KotlinCompile> {
    kotlinOptions {
        jvmTarget = "1.8"
        freeCompilerArgs = listOf("-Xjsr305=strict")
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    compile("org.jetbrains.kotlin:kotlin-reflect")
    compile("org.hibernate:hibernate-core")
    compile("com.h2database:h2")
}
./gradlew bootRun
curl http://localhost:8080/test_trigger

日志输出:

Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: select thing0_.id as id1_0_0_, thing0_.value as value2_0_0_ from thing thing0_ where thing0_.id=?
Hibernate: call next value for hibernate_sequence
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)
Hibernate: insert into thing (value, id) values (?, ?)

共有1个答案

司寇凯
2023-03-14

要使用Sring Boot和Spring Data JPA获得大容量插入,您只需要两件事:

>

  • 将选项spring.jpa.properties.hibernate.jdbc.batch_size设置为您需要的适当值(例如:20)。

    使用repo的saveAll()方法和准备插入的实体列表。

    INSERT INTO table VALUES (1, 2), (3, 4), (5, 6)
    

    这在PostgreSQL中可用:您可以在jdbc连接字符串中将rewriteBatchedInserts选项设置为true:

    jdbc:postgresql://localhost:5432/db?reWriteBatchedInserts=true
    

    然后jdbc驱动程序将进行此转换。

    关于批处理的其他信息可以在这里找到。

    如果使用Identity标识符生成器,Hibernate透明地禁用JDBC级别的插入批处理。

  •  类似资料:
    • 问题内容: 如果使用https://github.com/felixge/node- mysql之类的 东西,如何将大量插入MySQL中 问题答案: 使用嵌套数组可以进行大容量插入,请参见github页面 嵌套数组变成分组列表(用于批量插入),例如 变成 您只需插入一个嵌套的元素数组。 这里给出一个例子 注意:是一个包装在数组中的数组数组 还有用于批量插入的完全不同的node-msql软件包

    • 问题内容: 有没有一种方法可以使用JPA EntityManager使用批处理插入。我知道没有直接方法可以实现这一目标,但是必须有某种方法可以实现这一机制。 实际上,对于每一次插入操作,我要花300毫秒,我想减少使用批量插入而不是单次插入的时间。 这是我目前正在执行的用于单次插入的代码 提前致谢。 问题答案: 它 是 可以进行使用JPA成批写操作,但它是高度依赖于具体的实现你的持久性提供数据库和J

    • 问题内容: 如果使用https://github.com/felixge/node- mysql之类的 东西,如何将大量插入MySQL中 问题答案: 使用嵌套数组可以进行大容量插入,请参见github页面 嵌套数组变成分组列表(用于批量插入),例如 变成 您只需插入一个嵌套的元素数组。 这里给出一个例子 注意:是一个包装在数组中的数组数组 还有用于批量插入的完全不同的node-msql软件包

    • 问题内容: 我有许多记录需要输入到表中。在查询中执行此操作的最佳方法是什么?我是否应该进行循环并在每次迭代中插入一条记录?或者,还有更好的方法? 问题答案: 从MySQL手册 使用VALUES语法的INSERT语句可以插入多行。为此,请包括多个列值列表,每个列值括在括号内并用逗号分隔。例:

    • 问题内容: 错误: 违反主键约束。 无法在对象中插入重复的密钥。 如何使第一行之后的主键递增? 我希望能够同时向此表添加项目列表,而不是将其插入RBAR。 谢谢您的帮助 问题答案: 仅对于此语句,ID将是顺序的,例如,如果ID为99,并且要插入4条记录,则ID为100、101、102、103。如果同时插入多个进程,则很容易违反约束,但是这并不是说,这比使用单条记录本质上不安全的情况要糟。

    • 我正在为SQL Server使用大容量插入命令,但由于某些原因,第一行没有插入。为什么不能从第一行插入数据?大容量插入是否需要标头作为默认设置,如何规避?如果我添加一个虚拟行,并将设置为,那么插入第一行就没有问题了,但我认为这不是一个好的解决方案。 示例数据: