java - Spring在 "Executing identity-insert immediately"时不回滚

标签 java mysql spring hibernate

我在 Spring 回滚事务方面遇到问题。我有一个方法可以创建一个插入多个表的新订单(usersorderorder_product...)。如果在方法完成之前出现异常,则会启动回滚,并且 order_product 中的记录将被删除,但 users 记录仍然保留。我想删除数据库中生成的所有记录。 users 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
    }
}

最佳答案

在这里,您在每个 @Transactional 方法中执行每个数据库插入/更新步骤。此注释在该方法执行开始时创建一个数据库事务 session ,并在方法执行结束时提交。

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

您可以做的是,将所有这些代码放入一个用 @Transactional 注释的方法中

我会建议一个模式..

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

SUMMARY :使用@Transactional将单个方法执行期间的所有数据库查询放在一起,以便在发生运行时异常时自动回滚。

注意:您可以放置​​@Transactional、方法级别或类级别

关于java - Spring在 "Executing identity-insert immediately"时不回滚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41219191/

相关文章:

java - Java 中的类和继承——我做错了什么?

Java 在 drawRect 中 Swing 奇怪的额外像素

php - 需要使用 jQuery 显示包含数据库信息的数组元素

java - Spring 数据 JPA : persist a many to may relationship in both directions

java - 如何从 Spring JdbcTemplate 连接到受密码保护的 MS Access 数据库?

spring - Shiro 和 CAS 如何使用不同的域进行身份验证和授权?

java - java中如何引用扩展子类?

java - 反射将非空属性从一个对象复制到另一个 BeanUtils

MySQL - 判断列_all_是否具有相同的值

c# - DataGridView 不显示最近插入的行