【问题标题】:Cannot use delete() on CrudRepository不能在 CrudRepository 上使用 delete()
【发布时间】:2014-07-13 09:55:02
【问题描述】:

我第一次使用最新的 spring (4.0.4) 和 Hibernate (4.3.5) 和 spring-data-jpa (1.6.0),并且无法让存储库在 MySQL 表上工作写入或删除数据。它正在读取数据,但是当我尝试删除时,什么也没有发生。如果我使用 H2 数据库,一切正常,但是当我将数据源切换为 MySQL 服务器时,delete() 停止工作。

问题 1:为什么当我使用 MySQL 数据源时,CrudRepository 子类不能从我的表实体中删除行,但如果我使用 H2 数据源,它可以使用相同的代码?

如果我在我的 CrudRepository 子类中创建这样的函数,我可以删除数据:

public interface MyEntityRepository extends CrudRepository<MyEntity, Long> {
    @Modifying
    @Query("delete from MyEntity where entity_id = ?1")
    void delete(Long entityId);

    @Modifying
    @Query("delete from StageTeacher")
    void deleteAll();
}

我希望我错过了一些简单的东西。但是在我的单元测试类中,我有这个自动装配的存储库参考:

@Autowired
MyEntityRepository myEntityRepository;

当我使用 MySQL 数据源时,这些命令什么都不做(它们甚至不会出现运行时错误):

myEntityRepository.deleteAll();
myEntityRepository.delete(myEntity.getId());

这是 2 个数据源(H2 已被注释掉)和我使用此代码创建的实体管理器工厂:

@Bean
public EntityManagerFactory entityManagerFactory() throws SQLException {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://<host name>:3306/<schema name>");
    dataSource.setUsername("<username>");
    dataSource.setPassword("<password>");

    /*
    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
    DriverManagerDataSource dataSource = builder.setType(EmbeddedDatabaseType.H2).build();
    */

    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    // used when I have H2 enabled
    //vendorAdapter.setGenerateDdl(true);

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);

    Properties properties = new Properties();
    properties.setProperty("hibernate.show_sql", "true");
    properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLMyISAMDialect");
    factory.setJpaProperties(properties);

    factory.setPackagesToScan("<package with table entity classes>");
    factory.setDataSource(dataSource);
    factory.afterPropertiesSet();

    return factory.getObject();
}

编辑:我已将以下内容添加到我的 log4j.xml:

<logger name="org.hibernate">
    <level value="DEBUG"/>
</logger>
<logger name="org.springframework.data">
    <level value="DEBUG"/>
</logger>

当我在 Repository 子类中取消注释我的方法时,我会在控制台中得到这个:

DEBUG [main] IntegrationTests.delete(54) | >>>>>>>>>> delete all??
DEBUG [main] AbstractTransactionImpl.begin(160) | begin
DEBUG [main] LogicalConnectionImpl.obtainConnection(226) | Obtaining JDBC connection
DEBUG [main] LogicalConnectionImpl.obtainConnection(232) | Obtained JDBC connection
DEBUG [main] JdbcTransaction.doBegin(69) | initial autocommit status: true
DEBUG [main] JdbcTransaction.doBegin(71) | disabling autocommit
Hibernate: delete from stage_teacher
DEBUG [main] AbstractTransactionImpl.commit(175) | committing
DEBUG [main] JdbcTransaction.doCommit(113) | committed JDBC Connection
DEBUG [main] JdbcTransaction.releaseManagedConnection(126) | re-enabling autocommit
DEBUG [main] LogicalConnectionImpl.releaseConnection(246) | Releasing JDBC connection
DEBUG [main] LogicalConnectionImpl.releaseConnection(264) | Released JDBC connection

删除成功!

但是,如果我将存储库子类方法注释掉,我会在控制台中得到这个:

DEBUG [main] IntegrationTests.delete(54) | >>>>>>>>>> delete??
DEBUG [main] AbstractTransactionImpl.begin(160) | begin
DEBUG [main] LogicalConnectionImpl.obtainConnection(226) | Obtaining JDBC connection
DEBUG [main] LogicalConnectionImpl.obtainConnection(232) | Obtained JDBC connection
DEBUG [main] JdbcTransaction.doBegin(69) | initial autocommit status: true
DEBUG [main] JdbcTransaction.doBegin(71) | disabling autocommit
Hibernate: select stageteach0_.entity_id as entity_i1_0_0_, stageteach0_.active as active2_0_0_, stageteach0_.alias as alias3_0_0_, stageteach0_.allow_marketing_emails as allow_ma4_0_0_, stageteach0_.allow_password_resets as allow_pa5_0_0_, stageteach0_.console_setting_id as console_6_0_0_, stageteach0_.date_created as date_cre7_0_0_, stageteach0_.date_deactivated as date_dea8_0_0_, stageteach0_.date_modified as date_mod9_0_0_, stageteach0_.default_role_id as default10_0_0_, stageteach0_.district_teacher_id as distric11_0_0_, stageteach0_.email_address as email_a12_0_0_, stageteach0_.first_name as first_n13_0_0_, stageteach0_.first_name_localized as first_n14_0_0_, stageteach0_.iid as iid15_0_0_, stageteach0_.last_name as last_na16_0_0_, stageteach0_.last_name_localized as last_na17_0_0_, stageteach0_.main_teacher_id as main_te18_0_0_, stageteach0_.password as passwor19_0_0_, stageteach0_.pref_language_id as pref_la20_0_0_, stageteach0_.rest_id as rest_id21_0_0_, stageteach0_.salutation_id as salutat22_0_0_, stageteach0_.school_teacher_id as school_23_0_0_, stageteach0_.status_id as status_24_0_0_, stageteach0_.tcd as tcd25_0_0_, stageteach0_.teacher_type_id as teacher26_0_0_, stageteach0_.username as usernam27_0_0_ from stage_teacher stageteach0_ where stageteach0_.entity_id=?
DEBUG [main] ResultSetProcessorImpl.extractResults(127) | Starting ResultSet row #0
DEBUG [main] EntityReferenceInitializerImpl.resolveEntityKey(142) | On call to EntityIdentifierReaderImpl#resolve, EntityKey was already known; should only happen on root returns with an optional identifier specified
DEBUG [main] TwoPhaseLoad.doInitializeEntity(160) | Resolving associations for [org.mind.gen40.domain.gen40.StageTeacher#10956]
DEBUG [main] TwoPhaseLoad.doInitializeEntity(286) | Done materializing entity [org.mind.gen40.domain.gen40.StageTeacher#10956]
DEBUG [main] AbstractLoadPlanBasedEntityLoader.load(208) | Done entity load : org.mind.gen40.domain.gen40.StageTeacher#10956
DEBUG [main] AbstractTransactionImpl.commit(175) | committing
DEBUG [main] JdbcTransaction.doCommit(113) | committed JDBC Connection
DEBUG [main] JdbcTransaction.releaseManagedConnection(126) | re-enabling autocommit
DEBUG [main] LogicalConnectionImpl.releaseConnection(246) | Releasing JDBC connection
DEBUG [main] LogicalConnectionImpl.releaseConnection(264) | Released JDBC connection

删除失败是否与此消息有关?

On call to EntityIdentifierReaderImpl#resolve, EntityKey was already known; should only happen on root returns with an optional identifier specified

我不确定这意味着什么......

问题 2:我是否必须为每个需要基本 CRUD 操作的表子类 CrudRepository,或者我可以使用对表实体类的引用在运行时为给定的创建 CrudRepository桌子?

问题3:如果我需要在大量的CrudRepository子类上手动创建我的delete和insert方法,在MySQL中给定的表生成表实体和DAO或repository类有什么建议吗?强>

【问题讨论】:

  • “停止工作”具体是什么意思?你有任何例外吗?打开 Hibernate SQL 日志记录(DEBUG 级别)并发布它发出的实际 SQL 查询。
  • 当我在 CrudRepository 子类中没有 delete() 和 deleteAll() 方法(每个都有如上所示的 Modifying 和 Query 注释)时,我没有遇到任何异常。如果没有我在存储库子类中的方法,当我运行单元测试时,SQL 根本不会运行删除行,但也没有异常或失败。
  • 加快日志记录。某处会解释为什么它没有继续。
  • 您使用的是什么日志系统?你是如何启动应用程序的?
  • 我通过将其放入我的 log4j.xml 中记录了大量信息: .. 。 谢谢!我正在尝试通过此排序以查看仅与删除尝试相关的日志记录。

标签: java mysql spring jpa


【解决方案1】:

我发现问题的根源在于我正在使用单元测试运行我的代码。显然单元测试被设置为自动回滚的事务,但我找不到支持它的文档。我的单元测试是在表中创建一行,然后根据它的 ID 删除该行。它总是失败,因为它总是回滚事务。

如果您需要实际执行删除的单元测试,请添加 rollback(false) 注释,以便您的单元测试方法如下所示:

@Autowired
MyEntityRepository myEntityRepository;

@Test
@Rollback(false)
public void createAndThenDeleteRow() {
    MyEntity testRecord = new TestRecord( "fake", "data" );
    TestRecord savedRecord = myEntityRepository.save( testRecord );
    Long id = savedRecord.getId();
    TestRecord loadedRecord = myEntityRepository.findOne( id );
    assertNotNull( loadedRecord );
    myEntityRepository.delete( id );
    TestRecord reloadedRecord = myEntityRepository.findOne( id );
    assertNull( reloadedRecord );
}

【讨论】:

    猜你喜欢
    • 2017-11-11
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    • 2021-10-31
    • 1970-01-01
    • 2021-10-26
    相关资源
    最近更新 更多