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

Spring在"立即执行标识插入"时不回滚

宋岳
2023-03-14

我有一个问题与Spring回滚事务。我有一个方法,它创建一个新的订单插入几个表(用户订单order_product...)。如果在方法完成之前有一个异常,回滚被启动,在order_product中的记录被删除,但用户记录仍然存在。我想删除在我的数据库中生成的所有记录。用户id字段(主键)是由MySQL 5.6中的自动增量生成的。order_product的主键是两个外键。

用户表:

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `email` varchar(255) NOT NULL,
  `new_email` varchar(255) DEFAULT NULL,
  `allowed_newsletter` bit(1) NOT NULL DEFAULT b'1',
  `lastname` varchar(255) DEFAULT NULL,
  `phone` varchar(255) DEFAULT NULL,
  `lang` enum('en','de','fr','es') DEFAULT 'es',
  `creation_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `IDX_EMAIL` (`email`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1092 DEFAULT CHARSET=latin1;

订单产品表:

CREATE TABLE `order_product` (
  `product_id` int(11) NOT NULL,
  `order_id` int(11) NOT NULL,
  `detail_json` longtext,
  `shipping_date` datetime DEFAULT NULL,
  `order_product_status` enum('PaymentPending','ShippingPending','Sent','Cancelled') NOT NULL DEFAULT 'PaymentPending',
  `is_downloaded` bit(1) NOT NULL DEFAULT b'0',
  PRIMARY KEY (`product_id`,`order_id`),
  KEY `IDX_OP_PRODUCT_ID` (`product_id`) USING BTREE,
  KEY `IDX_OP_ORDER_ID` (`order_id`) USING BTREE,
  CONSTRAINT `FK_OP_ORDER_ID` FOREIGN KEY (`order_id`) REFERENCES `order_customer` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_OP_PRODUCT_ID` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

我使用的是MySQL 5.6、Hibernate 4和Spring 4。

日志文件相关:

[annotation.AnnotationTransactionAttributeSource(getTransactionAttribute:108)] Adding transactional method 'UsersDAOImpl.insertUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 
[jpa.JpaTransactionManager(doGetTransaction:334)] Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@395dbec7] for JPA transaction
[jpa.JpaTransactionManager(handleExistingTransaction:476)] Participating in existing transaction
[spi.ActionQueue(addResolvedEntityInsertAction:213)] Executing identity-insert immediately
[hibernate.SQL(logStatement:104)] 
    insert 
    into
        users
        (allowed_newsletter, email, lang, lastname, name, new_email, phone) 
    values
        (?, ?, ?, ?, ?, ?, ?)
2016-12-19 09:47:46,046 DEBUG (http-bio-8080-exec-3) [id.IdentifierGeneratorHelper(getGeneratedIdentity:93)] Natively generated identity: 1091
2016-12-19 09:47:46,047 DEBUG (http-bio-8080-exec-3) [spi.ActionQueue(addResolvedEntityInsertAction:213)] Executing identity-insert immediately
.....
... MORE INSERTs - SELECTs - etc ...
.....
[annotation.AnnotationTransactionAttributeSource(getTransactionAttribute:108)] Adding transactional method 'OrderProductServiceImpl.addNewOrderProduct' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
[jpa.JpaTransactionManager(doGetTransaction:334)] Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@395dbec7] for JPA transaction
[jpa.JpaTransactionManager(handleExistingTransaction:476)] Participating in existing transaction
[annotation.AnnotationTransactionAttributeSource(getTransactionAttribute:108)] Adding transactional method 'OrderProductDAOImpl.addNewOrderProduct' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
[jpa.JpaTransactionManager(doGetTransaction:334)] Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@395dbec7] for JPA transaction
[jpa.JpaTransactionManager(handleExistingTransaction:476)] Participating in existing transaction
[internal.AbstractSaveEventListener(saveWithGeneratedId:130)] Generated identifier: component[orderId,productId]{orderId=144, productId=2553}, using strategy: org.hibernate.id.CompositeNestedGeneratedValueGenerator
[writers.HstsHeaderWriter(writeHeaders:130)] Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@1d011fbb
[context.HttpSessionSecurityContextRepository(saveContext:352)] SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
[internal.SessionImpl(disconnect:566)] Disconnecting session
[internal.LogicalConnectionImpl(releaseConnection:232)] Releasing JDBC connection
[internal.LogicalConnectionImpl(releaseConnection:250)] Released JDBC connection
[jpa.JpaTransactionManager(processRollback:851)] Initiating transaction rollback
[jpa.JpaTransactionManager(doRollback:538)] Rolling back JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@395dbec7]
[spi.AbstractTransactionImpl(rollback:203)] rolling back
[jdbc.JdbcTransaction(doRollback:164)] rolled JDBC Connection
[jdbc.JdbcTransaction(releaseManagedConnection:126)] re-enabling autocommit
[internal.JdbcCoordinatorImpl(close:173)] HHH000420: Closing un-released batch
[jpa.JpaTransactionManager(doCleanupAfterCompletion:600)] Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@395dbec7] after transaction
[jpa.EntityManagerFactoryUtils(closeEntityManager:435)] Closing JPA EntityManager
[internal.LogicalConnectionImpl(releaseConnection:232)] Releasing JDBC connection
[internal.LogicalConnectionImpl(releaseConnection:250)] Released JDBC connection

编辑:

@Controller
public class OrderController {
    @ResponseStatus(value = HttpStatus.ACCEPTED)
    @Transactional
    public void finishPayment(...) {
       //Call to service methods
    }
}

@Service
@Transactional
public class UsersServiceImpl implements UsersService {
    public UsersEntity registerNewGuest(String username, String email, MCountryEntity countryEntity, String nickname, String lang) {
        // Insert User
    }
}

@Service
@Transactional
public class OrderProductServiceImpl implements OrderProductService {
    @Override
    public void addNewOrderProduct(OrderProductEntity orderProductEntity) {
        // Insert OrderProduct
    }
}

共有2个答案

桂宏旷
2023-03-14
html lang-html prettyprint-override">@Service
@Transactional(rollbackFor = Exception.class)
李兴庆
2023-03-14

这里是在每个@Transactional方法上执行每个db插入/更新步骤。此注释在执行该方法时创建一个db事务会话,并在方法执行结束时提交。

这里,您的每个db插入都在不同的数据库会话中。如果您想在运行时异常发生时回滚所有db更新,所有这些事务都应该在同一个会话中。但这里不是。这就是问题的原因。

你可以做的是,把所有这些代码放在一个注释为@Transactional的方法中

我会建议一种模式。。

  1. 制作一个DAO类层,其方法将直接连接到数据库(假设)并在其中包含查询。使用@Repository注释该类
  2. 将带有@Service注释的类用于带有@Transactional注释的方法。因此,这些方法中的每一种都将在同一个跨国会议上进行。现在,您可以在同一个服务方法中调用许多DAO方法。如果这些DAO方法中的任何一个出现运行时异常,所有内容都将回滚

摘要:在使用@Transactional执行单个方法的过程中放置所有db查询,以便在发生运行时异常时自动回滚。

注意:您可以将@Transactional、方法级或类级

 类似资料:
  • 嗨,我正在使用Spring AOP进行日志记录,我有以下两个方面@before和@afterreturn,不幸的是,这两个方面都打印相同的响应,这里的期望是@before打印方法输入和@afterreturning打印方法输出。

  • 问题内容: 如何从此代码获得结果 通过 for循环 通常的方法是这样的 问题答案: 如果您 确实 需要 动态表名 ,那么我可能会选择 记录 类型: 结果集的 类型(它是一个 记录 数组): 执行选择并返回 结果集 实例的函数: 然后,该函数可以与类似的东西一起使用:

  • 我在下面的查询中遇到了一个错误,它给出了一个符号(在使用循环的行中)。我正在尝试开发一个函数,该函数将动态参数作为表名、列名、表id,并用于其他表。

  • 问题内容: 和之间有什么区别 ? 问题答案: 从根本上说,它们执行相同的操作,这是提供一种在PL / SQL中执行DDL语句的机制,这是本机不支持的。如果内存对我有用,那么在Oracle 7版本的DBMS_UTILITY软件包中可以使用EXEC_DDL_STATEMENT,而在8中仅引入本机动态SQL(EXECUTE IMMEDIATE)。 有一些区别。EXECUTEIMMEDIATE主要是关于执

  • 本文向大家介绍深入浅析javascript立即执行函数,包括了深入浅析javascript立即执行函数的使用技巧和注意事项,需要的朋友参考一下 javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花; 当然,能理解各型各色的写法也是对javascript语言特性更进一步的深入理解。  JavaScript 函数语法 函数就是包裹在花括号中的代

  • 问题内容: 插入后如何在Oracle 12c中返回标识列(id)的值?似乎大多数方法都使用序列来获取插入项的ID。 问题答案: 只需使用 RETURNING 子句。 例如 - 测试用例 -