【问题标题】:Spring transactional method on test doesn't rollback测试中的 Spring 事务方法不回滚
【发布时间】:2016-09-07 22:32:13
【问题描述】:

我想知道交易在春季是如何运作的,而且我或多或少地学会了它(或者我认为我已经学会了它)。唯一没有得到的是:为了检查回滚如何发挥它的魔力,我创建了一个测试,该测试调用带有 @Transacional 注释的方法,该注释抛出异常并查看方法更改是否已保存,如从外部看到的那样。令我惊讶的是,更改似乎已提交。

这是代码:

import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import org.springframework.transaction.annotation.Transactional;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import repositories.files.ArchivoEnDisco;
import repositories.files.ArchivosEnDiscoRepo;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = GhcserviceapiApplication.class)
@WebAppConfiguration
public class PruebasSinTransacciones {

    @Autowired
    ArchivosEnDiscoRepo repositorio;

    @Test
    public void compruebaTransaccionSinVariable() {

        // I get one far away from the last.
        Long id = repositorio.count() + 10l;

        try {

            inTransacction(id);

            fail("Exception must be throw");

        } catch (Exception e) {

        }

        // I try to get the saved object
        ArchivoEnDisco aedOriginal = repositorio.findOne(id);

        assertThat("An exception ocurred so it doesn't have to find it", aedOriginal, nullValue());

    }

    @Transactional()
    private void inTransacction(Long id) throws Exception {

        repositorio.save(new ArchivoEnDisco(id, id + "A.txt"));

        throw new Exception();

    }

}

对我来说,作为一个例外,事务必须回滚,因此保存对象不需要存在于存储库中。但是当我运行测试时,find 方法返回保存的对象。有人可以说我错了吗?


注意:GhcserviceapiApplication 是一个用@SpringBootApplication 注释的类。 ArchivosEnDiscoRepoCrudRepository。我的 pom 中有 spring-boot-starter-data-jpahsqldb,但没有配置 jpa(所以我在内存中使用 hsqldb)。


编辑

因为@M,我已经分班了。 Deinum 注释,也尝试使用和具体的rollbackFor 参数但结果是一样的。

// ConTransacciones.java
// Also tried with Throwable.class
@Transactional(rollbackFor=CustomError.class)
public class ConTransacciones {

    public ArchivosEnDiscoRepo repositorio;

    public void enTransaccion(Long id) throws CustomError {

        repositorio.save(new ArchivoEnDisco(id, id + "A.txt"));

        throw new CustomError();

    }

}

// CustomError.java
public class CustomError extends Exception { }

// PruebasSinTransacciones.java
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = GhcserviceapiApplication.class)
@WebAppConfiguration
public class PruebasSinTransacciones {

    @Autowired
    ArchivosEnDiscoRepo repositorio;

    @Test
    public void compruebaTransaccionSinVariable() {

        ConTransacciones ct = new ConTransacciones();
        ct.repositorio = this.repositorio;

        Long id = repositorio.count() + 10l;

        try {

            ct.enTransaccion(id);

            fail("Debería haberse lanzado una excepción");

        } catch (Exception e) {

        }

        ArchivoEnDisco aedOriginal = repositorio.findOne(id);

        assertThat("La transacción no debería haber guardado el archivo", aedOriginal, nullValue());

    }

}

【问题讨论】:

  • 这是一个内部方法调用,所以你的@Transactional 几乎没用。除此之外,即使不是这样,它也不会起作用,因为@Transactional 在测试用例中不是这样工作的!此外,您没有测试任何与数据库相关的内容,您只是在测试一级缓存。最后@Transactional 将默认只回滚RuntimeExceptions 而不是Exceptions。
  • 是的,我并没有真正尝试测试我的数据库,这个测试只是一种测试我认为事务是如何完成的方法。你能解释一下@Transactional 在测试中有什么区别吗?

标签: spring transactions spring-data


【解决方案1】:

Spring Transaction 仅对 Checked 异常回滚,因为 Exception 是部分检查类,它不会回滚事务。 你可以使用@Transactional(rollbackFor="Throwable.class")。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-07
    • 2017-11-07
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    • 2015-06-19
    • 2011-10-04
    相关资源
    最近更新 更多