|
1 |
| -use crate::connection::ConnectOptions; |
| 1 | +use crate::connection::{ConnectOptions, Connection}; |
2 | 2 | use crate::error::Error;
|
3 | 3 | use crate::executor::Executor;
|
4 | 4 | use crate::migrate::MigrateError;
|
@@ -209,29 +209,49 @@ CREATE TABLE IF NOT EXISTS _sqlx_migrations (
|
209 | 209 | migration: &'m Migration,
|
210 | 210 | ) -> BoxFuture<'m, Result<Duration, MigrateError>> {
|
211 | 211 | Box::pin(async move {
|
| 212 | + // Use a single transaction for the actual migration script and the essential bookeeping so we never |
| 213 | + // execute migrations twice. See https://github.com/launchbadge/sqlx/issues/1966. |
| 214 | + // The `execution_time` however can only be measured for the whole transaction. This value _only_ exists for |
| 215 | + // data lineage and debugging reasons, so it is not super important if it is lost. So we initialize it to -1 |
| 216 | + // and update it once the actual transaction completed. |
| 217 | + let mut tx = self.begin().await?; |
212 | 218 | let start = Instant::now();
|
213 | 219 |
|
214 |
| - let res = self.execute(&*migration.sql).await; |
215 |
| - |
216 |
| - let elapsed = start.elapsed(); |
217 |
| - |
218 | 220 | // language=MySQL
|
219 | 221 | let _ = query(
|
220 | 222 | r#"
|
221 | 223 | INSERT INTO _sqlx_migrations ( version, description, success, checksum, execution_time )
|
222 |
| - VALUES ( ?, ?, ?, ?, ? ) |
| 224 | + VALUES ( ?, ?, TRUE, ?, -1 ) |
223 | 225 | "#,
|
224 | 226 | )
|
225 | 227 | .bind(migration.version)
|
226 | 228 | .bind(&*migration.description)
|
227 |
| - .bind(res.is_ok()) |
228 | 229 | .bind(&*migration.checksum)
|
| 230 | + .execute(&mut tx) |
| 231 | + .await?; |
| 232 | + |
| 233 | + let _ = tx.execute(&*migration.sql).await?; |
| 234 | + |
| 235 | + tx.commit().await?; |
| 236 | + |
| 237 | + // Update `elapsed_time`. |
| 238 | + // NOTE: The process may disconnect/die at this point, so the elapsed time value might be lost. We accept |
| 239 | + // this small risk since this value is not super important. |
| 240 | + |
| 241 | + let elapsed = start.elapsed(); |
| 242 | + |
| 243 | + let _ = query( |
| 244 | + r#" |
| 245 | + UPDATE _sqlx_migrations |
| 246 | + SET execution_time = ? |
| 247 | + WHERE version = ? |
| 248 | + "#, |
| 249 | + ) |
229 | 250 | .bind(elapsed.as_nanos() as i64)
|
| 251 | + .bind(migration.version) |
230 | 252 | .execute(self)
|
231 | 253 | .await?;
|
232 | 254 |
|
233 |
| - res?; |
234 |
| - |
235 | 255 | Ok(elapsed)
|
236 | 256 | })
|
237 | 257 | }
|
|
0 commit comments