不能在CrudRepository上使用delete()

时间:2014-05-23 22:50:06

标签: java mysql spring jpa

我第一次使用最新的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子类上手动创建删除和插入方法,那么在MySQL中为表生成表实体和DAO或存储库类是否有任何建议?

1 个答案:

答案 0 :(得分:6)

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

如果您需要实际执行删除的单元测试,请添加回滚(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 );
}