首页 > 解决方案 > Spring Hibernate - 不同事务之间的@Transactional

问题描述

我正在创建一个测试,并且基本上在一个@Transactional方法中执行不同的事务。

我添加 a Project,然后添加 a Task,最后将再次从数据库中获取项目以测试它是否已保存任务。

请注意我展示的案例是一个单元测试,但我更感兴趣的是修复事务方法而不是测试本身,因为我过去在“生产代码”中已经有了这个。

模型类:

@Entity
@Table(name = "Task")
data class Task(
        @Id
        @SequenceGenerator(name = "TaskSeq", sequenceName = "TaskSeq", initialValue = 100)
        @GeneratedValue(generator = "TaskSeq")
        val id: Long = 0,

        @Column(nullable = false)
        val name: String,

        val description: String,

        val inZ: LocalDateTime = LocalDateTime.now(),
        var outZ: LocalDateTime = JpaConstants.MAX_DATETIME,
        var completed: Boolean = false,

        @ManyToOne(cascade = [CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH])
        @JoinColumn(name = "projectId")
        var project: Project? = null
) {
}

@Entity
@Table(name = "Project")
data class Project(
        @Id
        @SequenceGenerator(name = "ProjectSeq", sequenceName = "ProjectSeq", initialValue = 100)
        @GeneratedValue(generator = "ProjectSeq")
        val id: Long = 0,

        @Column(nullable = false)
        var name: String,

        @OneToMany(mappedBy = "project", cascade = [CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH])
        val tasks: MutableList<Task> = Lists.mutable.empty()
) {

}

服务等级:

@Service
class ProjectServiceImpl(private val projectRepository: ProjectRepository) : ProjectService {

    override fun save(project: Project): Project {
        return projectRepository.save(project)
    }

}


@Service
class TaskServiceImpl(private val taskRepository: TaskRepository, private val projectRepository: ProjectRepository) : TaskService {


    override fun save(task: Task): Task {
        return taskRepository.save(task)
    }

    override fun addTaskToProject(projectId: Long, task: Task): Task {
        val project = projectRepository.findById(projectId).orElseThrow { RecordNotFoundException("Couldn't find project with id {$projectId}") }
        task.project = project

        return save(task)
    }
}

我正在尝试使用事务方法的类:

class TaskServiceImplTest : TaskApplicationTests() {

@Autowired
private lateinit var taskService: TaskService

@Autowired
private lateinit var taskRepository: TaskRepository

@Autowired
private lateinit var projectService: ProjectService


@Test
@Transactional
fun canInsertTaskToProject() {
    val project = projectService.save(Project(name = "Conquer Paris"))
    var task = Task(name = "Check how many people we need to hire", description = "")
    task = taskService.addTaskToProject(project.id, task)

    assertTrue(task.id > 0)
    val projects = projectService.findAll()
    assertEquals(1, projects.size())
    assertEquals(1, projects[0].tasks.size)
    assertEquals(task.id, projects[0].tasks[0].id)
}

如果我将 a 添加@Transactional(REQUIRES_NEW)到服务中的方法,它将起作用,但我不希望它就像在真实事务中调用此方法一样,我希望它相应地回滚。另外我想避免使用太多 REQUIRES_NEW 以避免将来出现问题

如果我@Transactional从测试方法中删除 ,当我在最后两行测试任务列表的大小时,它将不起作用,因为它们是惰性的。

使它工作的最佳方法是什么?我认为@Transactional当我使用 db 中的另一个命令时,它会获得尚未提交的最新更新。

如果需要,Java 中的代码也可以:)

提前致谢!

标签: springhibernatekotlin

解决方案


根据您的场景,您可以使用@TestEntityManager以便可以在事务上下文中管理每个测试。这个例子可以帮助你,

https://grokonez.com/testing/datajptest-with-spring-boot


推荐阅读