diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookConverter.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookConverter.kt index bb2443bbd..12b5daab4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookConverter.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookConverter.kt @@ -15,7 +15,7 @@ import org.gotson.komga.domain.persistence.BookRepository import org.gotson.komga.domain.persistence.LibraryRepository import org.gotson.komga.domain.persistence.MediaRepository import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional +import org.springframework.transaction.support.TransactionTemplate import java.io.FileNotFoundException import java.nio.file.FileAlreadyExistsException import java.util.zip.Deflater @@ -38,6 +38,7 @@ class BookConverter( private val bookRepository: BookRepository, private val mediaRepository: MediaRepository, private val libraryRepository: LibraryRepository, + private val transactionTemplate: TransactionTemplate, ) { private val convertibleTypes = listOf("application/x-rar-compressed; version=4") @@ -55,7 +56,6 @@ class BookConverter( fun getConvertibleBookIds(library: Library): Collection = bookRepository.findAllIdsByLibraryIdAndMediaTypes(library.id, convertibleTypes) - @Transactional fun convertToCbz(book: Book) { if (!libraryRepository.findById(book.libraryId).convertToCbz) return logger.info { "Book conversion is disabled for the library, it may have changed since the task was submitted, skipping" } @@ -127,8 +127,10 @@ class BookConverter( if (book.path.deleteIfExists()) logger.info { "Deleted converted file: ${book.path}" } - bookRepository.update(convertedBook) - mediaRepository.update(convertedMedia) + transactionTemplate.executeWithoutResult { + bookRepository.update(convertedBook) + mediaRepository.update(convertedMedia) + } } fun getMismatchedExtensionBookIds(library: Library): Collection = @@ -136,7 +138,6 @@ class BookConverter( bookRepository.findAllIdsByLibraryIdAndMismatchedExtension(library.id, mediaType, extension) } - @Transactional fun repairExtension(book: Book) { if (!libraryRepository.findById(book.libraryId).repairExtensions) return logger.info { "Repair extensions is disabled for the library, it may have changed since the task was submitted, skipping" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt index 651d097e5..578ec0bc7 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt @@ -22,6 +22,7 @@ import org.gotson.komga.infrastructure.image.ImageConverter import org.gotson.komga.infrastructure.image.ImageType import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional +import org.springframework.transaction.support.TransactionTemplate import java.io.File import java.nio.file.Files import java.nio.file.Paths @@ -39,28 +40,29 @@ class BookLifecycle( private val bookAnalyzer: BookAnalyzer, private val imageConverter: ImageConverter, private val eventPublisher: EventPublisher, + private val transactionTemplate: TransactionTemplate, ) { - @Transactional fun analyzeAndPersist(book: Book): Boolean { logger.info { "Analyze and persist book: $book" } val media = bookAnalyzer.analyze(book) - // if the number of pages has changed, delete all read progress for that book - mediaRepository.findById(book.id).let { previous -> - if (previous.status == Media.Status.OUTDATED && previous.pages.size != media.pages.size) { - readProgressRepository.deleteByBookId(book.id) + transactionTemplate.executeWithoutResult { + // if the number of pages has changed, delete all read progress for that book + mediaRepository.findById(book.id).let { previous -> + if (previous.status == Media.Status.OUTDATED && previous.pages.size != media.pages.size) { + readProgressRepository.deleteByBookId(book.id) + } } - } - mediaRepository.update(media) + mediaRepository.update(media) + } eventPublisher.publishEvent(DomainEvent.BookUpdated(book)) return media.status == Media.Status.READY } - @Transactional fun generateThumbnailAndPersist(book: Book) { logger.info { "Generate thumbnail and persist for book: $book" } try { @@ -70,7 +72,6 @@ class BookLifecycle( } } - @Transactional fun addThumbnailForBook(thumbnail: ThumbnailBook) { when (thumbnail.type) { ThumbnailBook.Type.GENERATED -> { @@ -97,7 +98,6 @@ class BookLifecycle( thumbnailsHouseKeeping(thumbnail.bookId) } - @Transactional fun getThumbnail(bookId: String): ThumbnailBook? { val selected = thumbnailBookRepository.findSelectedByBookIdOrNull(bookId) @@ -200,6 +200,7 @@ class BookLifecycle( } } + @Transactional fun deleteOne(book: Book) { logger.info { "Delete book id: ${book.id}" } @@ -215,6 +216,7 @@ class BookLifecycle( eventPublisher.publishEvent(DomainEvent.BookDeleted(book)) } + @Transactional fun deleteMany(books: Collection) { val bookIds = books.map { it.id } logger.info { "Delete book ids: $bookIds" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycle.kt index f4b5e353e..d4deade74 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/LibraryContentLifecycle.kt @@ -14,7 +14,7 @@ import org.gotson.komga.domain.persistence.SidecarRepository import org.gotson.komga.infrastructure.configuration.KomgaProperties import org.gotson.komga.infrastructure.language.notEquals import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional +import org.springframework.transaction.support.TransactionTemplate import java.nio.file.Paths import kotlin.time.measureTime @@ -33,9 +33,9 @@ class LibraryContentLifecycle( private val sidecarRepository: SidecarRepository, private val komgaProperties: KomgaProperties, private val taskReceiver: TaskReceiver, + private val transactionTemplate: TransactionTemplate, ) { - @Transactional fun scanRootFolder(library: Library) { logger.info { "Updating library: $library" } measureTime { @@ -94,10 +94,12 @@ class LibraryContentLifecycle( fileLastModified = newBook.fileLastModified, fileSize = newBook.fileSize ) - mediaRepository.findById(existingBook.id).let { - mediaRepository.update(it.copy(status = Media.Status.OUTDATED)) + transactionTemplate.executeWithoutResult { + mediaRepository.findById(existingBook.id).let { + mediaRepository.update(it.copy(status = Media.Status.OUTDATED)) + } + bookRepository.update(updatedBook) } - bookRepository.update(updatedBook) } } } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/MetadataLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/MetadataLifecycle.kt index 27e67a65e..c1743e8ae 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/MetadataLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/MetadataLifecycle.kt @@ -25,7 +25,6 @@ import org.gotson.komga.infrastructure.metadata.barcode.IsbnBarcodeProvider import org.gotson.komga.infrastructure.metadata.comicrack.ComicInfoProvider import org.gotson.komga.infrastructure.metadata.epub.EpubMetadataProvider import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional private val logger = KotlinLogging.logger {} @@ -48,7 +47,6 @@ class MetadataLifecycle( private val eventPublisher: EventPublisher, ) { - @Transactional fun refreshMetadata(book: Book, capabilities: List) { logger.info { "Refresh metadata for book: $book with capabilities: $capabilities" } val media = mediaRepository.findById(book.id) @@ -143,7 +141,6 @@ class MetadataLifecycle( } } - @Transactional fun refreshMetadata(series: Series) { logger.info { "Refresh metadata for series: $series" } @@ -233,7 +230,6 @@ class MetadataLifecycle( } } - @Transactional fun aggregateMetadata(series: Series) { logger.info { "Aggregate book metadata for series: $series" } diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesLifecycle.kt index f10da51e4..94cab3144 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/SeriesLifecycle.kt @@ -173,7 +173,6 @@ class SeriesLifecycle( eventPublisher.publishEvent(DomainEvent.ReadProgressSeriesDeleted(seriesId, user.id)) } - @Transactional fun getThumbnail(seriesId: String): ThumbnailSeries? { val selected = thumbnailsSeriesRepository.findSelectedBySeriesIdOrNull(seriesId) @@ -196,7 +195,6 @@ class SeriesLifecycle( return null } - @Transactional fun addThumbnailForSeries(thumbnail: ThumbnailSeries) { // delete existing thumbnail with the same url thumbnailsSeriesRepository.findAllBySeriesId(thumbnail.seriesId) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/BookDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/BookDao.kt index 65c626461..291d98a77 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/BookDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/BookDao.kt @@ -238,17 +238,14 @@ class BookDao( .execute() } - @Transactional override fun delete(bookId: String) { dsl.deleteFrom(b).where(b.ID.eq(bookId)).execute() } - @Transactional override fun delete(bookIds: Collection) { dsl.deleteFrom(b).where(b.ID.`in`(bookIds)).execute() } - @Transactional override fun deleteAll() { dsl.deleteFrom(b).execute() } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ReadListDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ReadListDao.kt index 792a8610c..b508c350f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ReadListDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ReadListDao.kt @@ -176,14 +176,12 @@ class ReadListDao( insertBooks(readList) } - @Transactional override fun removeBookFromAll(bookId: String) { dsl.deleteFrom(rlb) .where(rlb.BOOK_ID.eq(bookId)) .execute() } - @Transactional override fun removeBooksFromAll(bookIds: Collection) { dsl.deleteFrom(rlb) .where(rlb.BOOK_ID.`in`(bookIds)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesDao.kt index 511d6cac6..8a37ce52c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesDao.kt @@ -9,7 +9,6 @@ import org.jooq.Condition import org.jooq.DSLContext import org.jooq.impl.DSL import org.springframework.stereotype.Component -import org.springframework.transaction.annotation.Transactional import java.net.URL import java.time.LocalDateTime import java.time.ZoneId @@ -84,7 +83,6 @@ class SeriesDao( .map { it.toDomain() } } - @Transactional override fun insert(series: Series) { dsl.insertInto(s) .set(s.ID, series.id) @@ -95,7 +93,6 @@ class SeriesDao( .execute() } - @Transactional override fun update(series: Series) { dsl.update(s) .set(s.NAME, series.name) @@ -108,17 +105,14 @@ class SeriesDao( .execute() } - @Transactional override fun delete(seriesId: String) { dsl.deleteFrom(s).where(s.ID.eq(seriesId)).execute() } - @Transactional override fun deleteAll() { dsl.deleteFrom(s).execute() } - @Transactional override fun delete(seriesIds: Collection) { dsl.deleteFrom(s).where(s.ID.`in`(seriesIds)).execute() } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SidecarDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SidecarDao.kt index 643dea670..96339f191 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SidecarDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SidecarDao.kt @@ -7,7 +7,6 @@ import org.gotson.komga.jooq.Tables import org.gotson.komga.jooq.tables.records.SidecarRecord import org.jooq.DSLContext import org.springframework.stereotype.Component -import org.springframework.transaction.annotation.Transactional import java.net.URL @Component @@ -20,7 +19,6 @@ class SidecarDao( override fun findAll(): Collection = dsl.selectFrom(sc).fetch().map { it.toDomain() } - @Transactional override fun save(libraryId: String, sidecar: Sidecar) { dsl.insertInto(sc) .values( @@ -36,7 +34,6 @@ class SidecarDao( .execute() } - @Transactional override fun deleteByLibraryIdAndUrls(libraryId: String, urls: Collection) { dsl.deleteFrom(sc) .where(sc.LIBRARY_ID.eq(libraryId)) @@ -44,7 +41,6 @@ class SidecarDao( .execute() } - @Transactional override fun deleteByLibraryId(libraryId: String) { dsl.deleteFrom(sc) .where(sc.LIBRARY_ID.eq(libraryId)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ThumbnailBookDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ThumbnailBookDao.kt index e31bf366b..e91513aea 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ThumbnailBookDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ThumbnailBookDao.kt @@ -37,7 +37,6 @@ class ThumbnailBookDao( .map { it.toDomain() } .firstOrNull() - @Transactional override fun insert(thumbnail: ThumbnailBook) { dsl.insertInto(tb) .set(tb.ID, thumbnail.id) @@ -49,7 +48,6 @@ class ThumbnailBookDao( .execute() } - @Transactional override fun update(thumbnail: ThumbnailBook) { dsl.update(tb) .set(tb.BOOK_ID, thumbnail.bookId) @@ -76,22 +74,18 @@ class ThumbnailBookDao( .execute() } - @Transactional override fun delete(thumbnailBookId: String) { dsl.deleteFrom(tb).where(tb.ID.eq(thumbnailBookId)).execute() } - @Transactional override fun deleteByBookId(bookId: String) { dsl.deleteFrom(tb).where(tb.BOOK_ID.eq(bookId)).execute() } - @Transactional override fun deleteByBookIds(bookIds: Collection) { dsl.deleteFrom(tb).where(tb.BOOK_ID.`in`(bookIds)).execute() } - @Transactional override fun deleteByBookIdAndType(bookId: String, type: ThumbnailBook.Type) { dsl.deleteFrom(tb) .where(tb.BOOK_ID.eq(bookId)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ThumbnailSeriesDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ThumbnailSeriesDao.kt index c003d9fe5..147e672f6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ThumbnailSeriesDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ThumbnailSeriesDao.kt @@ -30,7 +30,6 @@ class ThumbnailSeriesDao( .map { it.toDomain() } .firstOrNull() - @Transactional override fun insert(thumbnail: ThumbnailSeries) { dsl.insertInto(ts) .set(ts.ID, thumbnail.id) @@ -55,17 +54,14 @@ class ThumbnailSeriesDao( .execute() } - @Transactional override fun delete(thumbnailSeriesId: String) { dsl.deleteFrom(ts).where(ts.ID.eq(thumbnailSeriesId)).execute() } - @Transactional override fun deleteBySeriesId(seriesId: String) { dsl.deleteFrom(ts).where(ts.SERIES_ID.eq(seriesId)).execute() } - @Transactional override fun deleteBySeriesIds(seriesIds: Collection) { dsl.deleteFrom(ts).where(ts.SERIES_ID.`in`(seriesIds)).execute() } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/transaction/TransactionConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/transaction/TransactionConfiguration.kt new file mode 100644 index 000000000..51ef3e271 --- /dev/null +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/transaction/TransactionConfiguration.kt @@ -0,0 +1,14 @@ +package org.gotson.komga.infrastructure.transaction + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.transaction.PlatformTransactionManager +import org.springframework.transaction.support.TransactionTemplate + +@Configuration +class TransactionConfiguration { + + @Bean + fun transactionTemplate(transactionManager: PlatformTransactionManager) = + TransactionTemplate(transactionManager) +}