Skip to content

Commit 7e26818

Browse files
refactor mysql bulk insert
1 parent 0055d27 commit 7e26818

File tree

3 files changed

+106
-29
lines changed

3 files changed

+106
-29
lines changed

ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/BulkInsert.kt

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ import org.ktorm.schema.Column
3030
/**
3131
* Bulk insert expression, represents a bulk insert statement in MySQL.
3232
*
33-
* For example: `insert into table (column1, column2) values (?, ?), (?, ?), (?, ?)...`.
33+
* For example:
34+
*
35+
* ```sql
36+
* insert into table (column1, column2) values (?, ?), (?, ?), (?, ?)...
37+
* on duplicate key update ...
38+
* ```
3439
*
3540
* @property table the table to be inserted.
3641
* @property assignments column assignments of the bulk insert statement.
@@ -82,21 +87,90 @@ public data class BulkInsertExpression(
8287
* @return the effected row count.
8388
* @see batchInsert
8489
*/
85-
public fun <T : BaseTable<*>> Database.bulkInsert(table: T, block: BulkInsertStatementBuilder<T>.() -> Unit): Int {
90+
public fun <T : BaseTable<*>> Database.bulkInsert(
91+
table: T, block: BulkInsertStatementBuilder<T>.() -> Unit
92+
): Int {
8693
val builder = BulkInsertStatementBuilder(table).apply(block)
8794

88-
val expr = AliasRemover.visit(
95+
val expression = AliasRemover.visit(
8996
BulkInsertExpression(table.asExpression(), builder.assignments, builder.updateAssignments)
9097
)
9198

92-
return executeUpdate(expr)
99+
return executeUpdate(expression)
100+
}
101+
102+
/**
103+
* Bulk insert records to the table, determining if there is a key conflict while inserting each of them,
104+
* and automatically performs updates if any conflict exists.
105+
*
106+
* Usage:
107+
*
108+
* ```kotlin
109+
* database.bulkInsertOrUpdate(Employees) {
110+
* item {
111+
* set(it.id, 1)
112+
* set(it.name, "vince")
113+
* set(it.job, "engineer")
114+
* set(it.salary, 1000)
115+
* set(it.hireDate, LocalDate.now())
116+
* set(it.departmentId, 1)
117+
* }
118+
* item {
119+
* set(it.id, 5)
120+
* set(it.name, "vince")
121+
* set(it.job, "engineer")
122+
* set(it.salary, 1000)
123+
* set(it.hireDate, LocalDate.now())
124+
* set(it.departmentId, 1)
125+
* }
126+
* onDuplicateKey {
127+
* set(it.salary, it.salary + 900)
128+
* }
129+
* }
130+
* ```
131+
*
132+
* Generated SQL:
133+
*
134+
* ```sql
135+
* insert into t_employee (id, name, job, salary, hire_date, department_id)
136+
* values (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?)
137+
* on duplicate key update salary = t_employee.salary + ?
138+
* ```
139+
*
140+
* @since 3.3.0
141+
* @param table the table to be inserted.
142+
* @param block the DSL block used to construct the expression.
143+
* @return the effected row count.
144+
* @see bulkInsert
145+
*/
146+
public fun <T : BaseTable<*>> Database.bulkInsertOrUpdate(
147+
table: T, block: BulkInsertOrUpdateStatementBuilder<T>.() -> Unit
148+
): Int {
149+
val builder = BulkInsertOrUpdateStatementBuilder(table).apply(block)
150+
151+
val expression = AliasRemover.visit(
152+
BulkInsertExpression(table.asExpression(), builder.assignments, builder.updateAssignments)
153+
)
154+
155+
return executeUpdate(expression)
93156
}
94157

95158
/**
96159
* DSL builder for bulk insert statements.
97160
*/
161+
public class BulkInsertStatementBuilder<T : BaseTable<*>>(table: T) : BulkInsertOrUpdateStatementBuilder<T>(table) {
162+
163+
@Deprecated("This function will be removed in the future, please use bulkInsertOrUpdate instead of bulkInsert.")
164+
override fun onDuplicateKey(block: BulkInsertOrUpdateOnDuplicateKeyClauseBuilder.(T) -> Unit) {
165+
super.onDuplicateKey(block)
166+
}
167+
}
168+
169+
/**
170+
* DSL builder for bulk insert or update statements.
171+
*/
98172
@KtormDsl
99-
public class BulkInsertStatementBuilder<T : BaseTable<*>>(internal val table: T) {
173+
public open class BulkInsertOrUpdateStatementBuilder<T : BaseTable<*>>(internal val table: T) {
100174
internal val assignments = ArrayList<List<ColumnAssignmentExpression<*>>>()
101175
internal val updateAssignments = ArrayList<ColumnAssignmentExpression<*>>()
102176

@@ -119,18 +193,18 @@ public class BulkInsertStatementBuilder<T : BaseTable<*>>(internal val table: T)
119193
/**
120194
* Specify the update assignments while any key conflict exists.
121195
*/
122-
public fun onDuplicateKey(block: BulkInsertOnDuplicateKeyClauseBuilder.(T) -> Unit) {
123-
val builder = BulkInsertOnDuplicateKeyClauseBuilder()
196+
public open fun onDuplicateKey(block: BulkInsertOrUpdateOnDuplicateKeyClauseBuilder.(T) -> Unit) {
197+
val builder = BulkInsertOrUpdateOnDuplicateKeyClauseBuilder()
124198
builder.block(table)
125199
updateAssignments += builder.assignments
126200
}
127201
}
128202

129203
/**
130-
* DSL builder for bulk insert on duplicate key clause.
204+
* DSL builder for bulk insert or update on duplicate key clause.
131205
*/
132206
@KtormDsl
133-
public class BulkInsertOnDuplicateKeyClauseBuilder : MySqlAssignmentsBuilder() {
207+
public class BulkInsertOrUpdateOnDuplicateKeyClauseBuilder : MySqlAssignmentsBuilder() {
134208

135209
/**
136210
* Use VALUES() function in a ON DUPLICATE KEY UPDATE clause.

ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/InsertOrUpdate.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ import org.ktorm.expression.TableExpression
2626
import org.ktorm.schema.BaseTable
2727

2828
/**
29-
* Insert or update expression, represents an insert statement with an `on duplicate key update` clause in MySQL.
29+
* Insert or update expression, represents an insert statement with an
30+
* `on duplicate key update` clause in MySQL.
3031
*
3132
* @property table the table to be inserted.
3233
* @property assignments the inserted column assignments.
@@ -73,16 +74,15 @@ public data class InsertOrUpdateExpression(
7374
* @return the effected row count.
7475
*/
7576
public fun <T : BaseTable<*>> Database.insertOrUpdate(
76-
table: T,
77-
block: InsertOrUpdateStatementBuilder.(T) -> Unit
77+
table: T, block: InsertOrUpdateStatementBuilder.(T) -> Unit
7878
): Int {
7979
val builder = InsertOrUpdateStatementBuilder().apply { block(table) }
8080

81-
val expr = AliasRemover.visit(
81+
val expression = AliasRemover.visit(
8282
InsertOrUpdateExpression(table.asExpression(), builder.assignments, builder.updateAssignments)
8383
)
8484

85-
return executeUpdate(expr)
85+
return executeUpdate(expression)
8686
}
8787

8888
/**

ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/BulkInsert.kt

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ import org.ktorm.schema.Column
3131
* Bulk insert expression, represents a bulk insert statement in PostgreSQL.
3232
*
3333
* For example:
34-
* `insert into table (column1, column2) values (?, ?), (?, ?), (?, ?)... on conflict (...) do update set ...`.
34+
*
35+
* ```sql
36+
* insert into table (column1, column2) values (?, ?), (?, ?), (?, ?)...
37+
* on conflict (...) do update set ...`
38+
* ```
3539
*
3640
* @property table the table to be inserted.
3741
* @property assignments column assignments of the bulk insert statement.
@@ -48,12 +52,11 @@ public data class BulkInsertExpression(
4852
) : SqlExpression()
4953

5054
/**
51-
* Construct a bulk insert expression in the given closure, then execute it and return the
52-
* effected row count.
55+
* Construct a bulk insert expression in the given closure, then execute it and return the effected row count.
5356
*
54-
* The usage is almost the same as [batchInsert], but this function is implemented by generating a
55-
* special SQL using PostgreSQL's bulk insert syntax, instead of based on JDBC batch operations.
56-
* For this reason, its performance is much better than [batchInsert].
57+
* The usage is almost the same as [batchInsert], but this function is implemented by generating a special SQL
58+
* using PostgreSQL's bulk insert syntax, instead of based on JDBC batch operations. For this reason, its performance
59+
* is much better than [batchInsert].
5760
*
5861
* The generated SQL is like: `insert into table (column1, column2) values (?, ?), (?, ?), (?, ?)...`.
5962
*
@@ -62,20 +65,20 @@ public data class BulkInsertExpression(
6265
* ```kotlin
6366
* database.bulkInsert(Employees) {
6467
* item {
65-
* set(it.id, 1)
66-
* set(it.name, "vince")
67-
* set(it.job, "engineer")
68-
* set(it.salary, 1000)
68+
* set(it.name, "jerry")
69+
* set(it.job, "trainee")
70+
* set(it.managerId, 1)
6971
* set(it.hireDate, LocalDate.now())
72+
* set(it.salary, 50)
7073
* set(it.departmentId, 1)
7174
* }
7275
* item {
73-
* set(it.id, 5)
74-
* set(it.name, "vince")
75-
* set(it.job, "engineer")
76-
* set(it.salary, 1000)
76+
* set(it.name, "linda")
77+
* set(it.job, "assistant")
78+
* set(it.managerId, 3)
7779
* set(it.hireDate, LocalDate.now())
78-
* set(it.departmentId, 1)
80+
* set(it.salary, 100)
81+
* set(it.departmentId, 2)
7982
* }
8083
* }
8184
* ```

0 commit comments

Comments
 (0)