diff --git a/application/src/main/java/run/halo/app/core/extension/service/UserServiceImpl.java b/application/src/main/java/run/halo/app/core/extension/service/UserServiceImpl.java index 1924b37b2..eb5594637 100644 --- a/application/src/main/java/run/halo/app/core/extension/service/UserServiceImpl.java +++ b/application/src/main/java/run/halo/app/core/extension/service/UserServiceImpl.java @@ -18,7 +18,6 @@ import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.data.domain.Sort; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -147,7 +146,6 @@ public class UserServiceImpl implements UserService { } @Override - @Transactional public Mono signUp(User user, String password) { if (!StringUtils.hasText(password)) { throw new IllegalArgumentException("Password must not be blank"); diff --git a/application/src/main/java/run/halo/app/extension/ReactiveExtensionClientImpl.java b/application/src/main/java/run/halo/app/extension/ReactiveExtensionClientImpl.java index 5096bb1de..7187a96b9 100644 --- a/application/src/main/java/run/halo/app/extension/ReactiveExtensionClientImpl.java +++ b/application/src/main/java/run/halo/app/extension/ReactiveExtensionClientImpl.java @@ -312,6 +312,44 @@ public class ReactiveExtensionClientImpl implements ReactiveExtensionClient { return this.indexedQueryEngine; } + /** + *

Note of transactional:

+ *

doSomething does not have a transaction, but methodOne and methodTwo have their own + * transactions.

+ *

If methodTwo fails and throws an exception, the transaction in methodTwo will be rolled + * back, but the transaction in methodOne will not.

+ *
+     * public void doSomething() {
+     *     // with manual transaction
+     *     methodOne();
+     *     // with manual transaction
+     *     methodTwo();
+     * }
+     * 
+ *

If doSomething is annotated with @Transactional, both methodOne and methodTwo will be + * executed within the same transaction context.

+ *

If methodTwo fails and throws an exception, the entire transaction will be rolled back, + * including any changes made by methodOne.

+ *

This ensures that all operations within the doSomething method either succeed or fail + * together.

+ *

This example advises against adding transaction annotations to the outer method that + * invokes {@link #update(Extension)} or {@link #create(Extension)}, as doing so could + * undermine the intended transactional integrity of this method.

+ * + *

Note another point:

+ * After executing the {@code client.create(name, data)} method, an attempt is made to + * indexRecord. However, indexRecord might fail due to duplicate keys in the unique index, + * causing the index creation to fail. In such cases, the data created by {@code client + * .create(name, data)} should be rolled back to maintain consistency between the index and + * the data. + *

Until a better solution is found for this consistency problem, do not remove the + * manual transaction here.

+ *
+     * client.create(name, data)
+     *  .doOnNext(extension -> indexer.indexRecord(convertToRealExtension(extension)))
+     *  .as(transactionalOperator::transactional);
+     * 
+ */ @SuppressWarnings("unchecked") Mono doCreate(E oldExtension, String name, byte[] data) { return Mono.defer(() -> { @@ -325,6 +363,9 @@ public class ReactiveExtensionClientImpl implements ReactiveExtensionClient { }); } + /** + * see also {@link #doCreate(Extension, String, byte[])}. + */ @SuppressWarnings("unchecked") Mono doUpdate(E oldExtension, String name, Long version, byte[] data) { return Mono.defer(() -> { diff --git a/application/src/main/java/run/halo/app/extension/store/ReactiveExtensionStoreClientImpl.java b/application/src/main/java/run/halo/app/extension/store/ReactiveExtensionStoreClientImpl.java index 8e7b4ce8a..465245e28 100644 --- a/application/src/main/java/run/halo/app/extension/store/ReactiveExtensionStoreClientImpl.java +++ b/application/src/main/java/run/halo/app/extension/store/ReactiveExtensionStoreClientImpl.java @@ -8,7 +8,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import run.halo.app.infra.exception.DuplicateNameException; @@ -61,7 +60,6 @@ public class ReactiveExtensionStoreClientImpl implements ReactiveExtensionStoreC } @Override - @Transactional public Mono delete(String name, Long version) { return repository.findById(name) .flatMap(extensionStore -> { diff --git a/application/src/main/java/run/halo/app/migration/impl/MigrationServiceImpl.java b/application/src/main/java/run/halo/app/migration/impl/MigrationServiceImpl.java index 6d21b50ba..700bbd076 100644 --- a/application/src/main/java/run/halo/app/migration/impl/MigrationServiceImpl.java +++ b/application/src/main/java/run/halo/app/migration/impl/MigrationServiceImpl.java @@ -29,7 +29,6 @@ import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebInputException; import reactor.core.Exceptions; @@ -136,7 +135,6 @@ public class MigrationServiceImpl implements MigrationService, InitializingBean } @Override - @Transactional public Mono restore(Publisher content) { return Mono.usingWhen( createTempDir("halo-restore-", scheduler),