Junit+Hibernate+Spring+H2 :inserts 执行没有错误但是 select 没有返回数据

Posted

技术标签:

【中文标题】Junit+Hibernate+Spring+H2 :inserts 执行没有错误但是 select 没有返回数据【英文标题】:Junit+Hibernate+Spring+H2 :inserts were executed without errors but select returns no data 【发布时间】:2013-01-11 14:39:30 【问题描述】:

我正在尝试使用内存数据库 H2 对我的代码中的事务进行 junit 测试。 一切看起来都很好 - 表是从 hbm2ddl 创建的,执行了插入但 select 返回 null。

Junit 在线测试失败:

  assertNotNull(artifactManager.getArtifact(id));

整体测试

@Test
@Transactional()
@Rollback(true)
public void failTransactionOnUpdateArtifactStateArtifactVerification() throws IllegalStateException, IOException 
    //GIVEN
    //some initialization already happened
    artifactManager.saveArtifact(artifact);

    //WHEN
    HibernateException exc = Mockito.mock(HibernateException.class);
    Mockito.when(historyDao.saveArtifactInHistory(artifact, ver)).thenThrow(exc);

    //THEN
    //artifact should be present in DB
    assertNotNull(artifactManager.getArtifact(id));
    assertEquals(artifactManager.getArtifact(id).getState().getType(),StateTypes.SENT);

    //and after exception rollback on artifacts Table should be performed and no artifacts should be present in DB
    try
        stateService.updateArtifactState( ver,artifact);
    catch(Exception e)
        e.printStackTrace();
    
    //updateArtifact(artifact); should be rolled back and state reverted to SENT
    assertEquals(artifactManager.getArtifact(id).getState().getType(),StateTypes.SENT);

控制台日志的相关部分:

2013-01-11 15:02:21,538 INFO [org.hibernate.tool.hbm2ddl.SchemaUpdate] - <schema update complete>
2013-01-11 15:02:21,934 INFO [org.acegisecurity.intercept.AbstractSecurityInterceptor] - <Validated configuration attributes>    Hibernate: select artifact0_.Id as Id99_4_, artifact0_.CrosscheckerID as Crossche7_99_4_, artifact0_.CategoryID as CategoryID99_4_, artifact0_.CreationDate as Creation2_99_4_, artifact0_.Description as Descript3_99_4_, artifact0_.FileChecksum as FileChec4_99_4_, artifact0_.ReportID as ReportID99_4_, artifact0_.StateID as StateID99_4_, artifact0_.StateChangeDate as StateCha5_99_4_, artifact0_.Storage as Storage99_4_, user1_.ID as ID86_0_, user1_.Name as Name86_0_, user1_.Surname as Surname86_0_, user1_.username as username86_0_, user1_.jobPositionID as jobPosit5_86_0_, user1_.Email as Email86_0_, user1_.NSNID as NSNID86_0_, user1_.PESEL as PESEL86_0_, user1_.NIP as NIP86_0_, user1_.InProgram as InProgram86_0_, user1_.Employeed as Employeed86_0_, user1_.OutsidePoland as Outside12_86_0_, user1_.Password as Password86_0_, user1_.IncomeCosts as IncomeC14_86_0_, user1_.SupervisorID as Supervi15_86_0_, user1_.Disclosure as Disclosure86_0_, user1_.UserState as UserState86_0_, user1_.FailedLoginAttempts as FailedL18_86_0_, user1_.LastFailedLoginAttempt as LastFai19_86_0_, category2_.ID as ID107_1_, category2_.Name as Name107_1_, category2_."Order" as Order3_107_1_, report3_.ID as ID88_2_, report3_.UserID as UserID88_2_, report3_.StateID as StateID88_2_, report3_.CreationDate as Creation4_88_2_, report3_.StateChangeDate as StateCha5_88_2_, report3_.SupervisorID as Supervis6_88_2_, report3_.AccepterId as AccepterId88_2_, report3_.IncomeCosts as IncomeCo8_88_2_, report3_.AccInProg as AccInProg88_2_, state4_.ID as ID89_3_, state4_.Name as Name89_3_ from Artifacts artifact0_ left outer join Users user1_ on artifact0_.CrosscheckerID=user1_.ID left outer join Categories category2_ on artifact0_.CategoryID=category2_.ID left outer join Reports report3_ on artifact0_.ReportID=report3_.ID left outer join States state4_ on artifact0_.StateID=state4_.ID where artifact0_.Id=?
Hibernate: select max(ID) from Reports
Hibernate: select state0_.ID as ID89_0_, state0_.Name as Name89_0_ from States state0_ where state0_.ID=?
Hibernate: select max(ID) from States
Hibernate: insert into Reports (UserID, StateID, CreationDate, StateChangeDate, SupervisorID, AccepterId, IncomeCosts, AccInProg, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into States (Name, ID) values (?, ?)
Hibernate: insert into Artifacts (Id, CrosscheckerID, CategoryID, CreationDate, Description, FileChecksum, ReportID, StateID, StateChangeDate, Storage) values (null, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select artifact0_.Id as Id99_5_, artifact0_.CrosscheckerID as Crossche7_99_5_, artifact0_.CategoryID as CategoryID99_5_, artifact0_.CreationDate as Creation2_99_5_, artifact0_.Description as Descript3_99_5_, artifact0_.FileChecksum as FileChec4_99_5_, artifact0_.ReportID as ReportID99_5_, artifact0_.StateID as StateID99_5_, artifact0_.StateChangeDate as StateCha5_99_5_, artifact0_.Storage as Storage99_5_, user1_.ID as ID86_0_, user1_.Name as Name86_0_, user1_.Surname as Surname86_0_, user1_.username as username86_0_, user1_.jobPositionID as jobPosit5_86_0_, user1_.Email as Email86_0_, user1_.NSNID as NSNID86_0_, user1_.PESEL as PESEL86_0_, user1_.NIP as NIP86_0_, user1_.InProgram as InProgram86_0_, user1_.Employeed as Employeed86_0_, user1_.OutsidePoland as Outside12_86_0_, user1_.Password as Password86_0_, user1_.IncomeCosts as IncomeC14_86_0_, user1_.SupervisorID as Supervi15_86_0_, user1_.Disclosure as Disclosure86_0_, user1_.UserState as UserState86_0_, user1_.FailedLoginAttempts as FailedL18_86_0_, user1_.LastFailedLoginAttempt as LastFai19_86_0_, category2_.ID as ID107_1_, category2_.Name as Name107_1_, category2_."Order" as Order3_107_1_, report3_.ID as ID88_2_, report3_.UserID as UserID88_2_, report3_.StateID as StateID88_2_, report3_.CreationDate as Creation4_88_2_, report3_.StateChangeDate as StateCha5_88_2_, report3_.SupervisorID as Supervis6_88_2_, report3_.AccepterId as AccepterId88_2_, report3_.IncomeCosts as IncomeCo8_88_2_, report3_.AccInProg as AccInProg88_2_, user4_.ID as ID86_3_, user4_.Name as Name86_3_, user4_.Surname as Surname86_3_, user4_.username as username86_3_, user4_.jobPositionID as jobPosit5_86_3_, user4_.Email as Email86_3_, user4_.NSNID as NSNID86_3_, user4_.PESEL as PESEL86_3_, user4_.NIP as NIP86_3_, user4_.InProgram as InProgram86_3_, user4_.Employeed as Employeed86_3_, user4_.OutsidePoland as Outside12_86_3_, user4_.Password as Password86_3_, user4_.IncomeCosts as IncomeC14_86_3_, user4_.SupervisorID as Supervi15_86_3_, user4_.Disclosure as Disclosure86_3_, user4_.UserState as UserState86_3_, user4_.FailedLoginAttempts as FailedL18_86_3_, user4_.LastFailedLoginAttempt as LastFai19_86_3_, state5_.ID as ID89_4_, state5_.Name as Name89_4_ from Artifacts artifact0_ left outer join Users user1_ on artifact0_.CrosscheckerID=user1_.ID left outer join Categories category2_ on artifact0_.CategoryID=category2_.ID left outer join Reports report3_ on artifact0_.ReportID=report3_.ID left outer join Users user4_ on report3_.UserID=user4_.ID left outer join States state5_ on artifact0_.StateID=state5_.ID where artifact0_.Id=?
2013-01-11 15:02:22,213 INFO [org.hibernate.impl.SessionFactoryImpl] - <closing>

我的数据库配置如下:

<bean id="dataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:mem:taxMemDB;DB_CLOSE_DELAY=-1" />
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>
<bean id="taxSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" >
    <property name="AnnotatedClasses">
        <list>    ...</list>
    </property>
    <property name="dataSource" ref="dataSource" />
    <property name="mappingResources">
        <list>
            <value>mapping.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=org.hibernate.dialect.H2Dialect
            hibernate.connection.charSet=UTF-8
            hibernate.connection.pool_size=15
            hibernate.show_sql=true
            hibernate.hbm2ddl.auto=update
        </value>
    </property>         
</bean>
<bean id="hibernateTemplate"
    class="org.springframework.orm.hibernate3.HibernateTemplate">
    <property name="sessionFactory">
        <ref bean="taxSessionFactory" />
    </property>
</bean>

任何线索可能是错的?还是我应该附加更多代码?

--请求的代码 工件管理器:

 public Artifact getArtifact(long artifactId) 
    Artifact artifact = artifactDao.getArtifact(artifactId);
    return artifact;

ArtifactDao:

@Override
public Artifact getArtifact(Long id) 
    Session session = sessionFactory.getCurrentSession();
    return (Artifact) session.get(Artifact.class, id);

ArtifactManager.saveArifact:

 @Transactional(rollbackFor = Exception.class)
public boolean saveArtifact(Artifact artifact)throws IOException 

    String checksum = null;
    String userPath = null;

        checksum = checksumGenerator.generateChecksum(artifact.getFile().getInputStream());
        userPath = storageManager.upload(artifact);
        artifact.setStoragePath(userPath);
        artifact.setFileChecksum(checksum);
        if(artifact.getId()!=null)
            return  artifactDao.mergeArtifact(artifact);
        else
            return artifactDao.saveOrUpdateArtifact(artifact);
        

ArifactDao 部分

@Override
public boolean saveOrUpdateArtifact(Artifact artifact) 
    Session session = sessionFactory.getCurrentSession();
    try 
        session.saveOrUpdate(artifact);
     catch (DataAccessException ex) 
        log.error(ex.getMessage());
        return false;
    
    return true;


@Override
public boolean mergeArtifact(Artifact artifact) 
    Session session = sessionFactory.getCurrentSession();
    try 
        session.merge(artifact);
     catch (DataAccessException ex) 
        log.error(ex.getMessage());
        return false;
    
    return true;

【问题讨论】:

能否贴出 artifactManager.getArtifact(id) 的代码 您在日志文件中的插入语句显示正在为一个值插入一个空值。在您获取工件之前设置的 id 是什么?它是一个生成的值。此外,您的模拟看起来也有点可疑,因为他们没有在何时使用匹配项。 我已经添加了请求的代码。插入中的空值也困扰着我,但工件是用 id(10L) 初始化的,即使调试器显示是正确的,但似乎休眠没有看到它..奇怪 【参考方案1】:

我认为您的方法 ArtifactManager.getArtifact(id) 正在直接查看数据库,并且由于您的事务尚未提交......它什么也没找到。

注意@Rollback(true) 表示你的事务永远不会被提交。

编辑

根据您的代码,您似乎正在寻找当前会话以查找工件(因此,未提交事务的 OK 事件)。

其他一些对检查有用的代码:

如何在映射中指定工件的 ID? (自动生成还是手动定义?) saveArtifact 方法的代码是什么?

编辑

我发现你的代码有一些烦人的地方:

您正在调用saveArtifact,但您没有检查返回值。在做任何其他事情之前最好检查一下。类似assertTrue(artifactManager.saveArtifact(artifact)));

通常,在合并实例时,将合并后的实例取回是很有趣的……但在您的 DAO 中,您会忘记它并返回一个布尔值。见merge API,真正有趣的是这个

给定的实例(即参数)不会与会话关联

根据您的 cmets,该工件使用 id=10L 进行初始化。因此,您将调用 session.merge 方法。但是您的工件不应该在会话中,也不应该在数据库中......所以我认为您应该在某处有一些相关的错误日志?没有?

【讨论】:

谢谢,可能是这样,我会用不同的交易填满表格,如果您的提示有效,请告诉您。 在本例中没有错误,但我遵循了您的第一个建议并在单独的事务中初始化了数据库,这有帮助,现在的问题是休眠在预期异常后不执行回滚(不能回滚休眠事务;事务未开始)

以上是关于Junit+Hibernate+Spring+H2 :inserts 执行没有错误但是 select 没有返回数据的主要内容,如果未能解决你的问题,请参考以下文章

Spring Hibernate H2 Junit 测试 - 如何在启动时加载模式

防止在 JUnit 中执行 jpa @Query

Spring4 JUnit 测试:将 SQL 加载到 H2 数据库

使用 h2 进行 Spring Junit 测试 - 找不到表

JUnit4、Spring、Hibernate 测试上下文设置

使用 H2 DB 进行 Spring/Hibernate 集成测试