【问题标题】:Hibernate | Why is the transaction "half-committed"休眠 |为什么事务“半提交”
【发布时间】:2018-10-25 08:05:59
【问题描述】:

我在 Spring Boot 项目中使用 Hibernate。

我有以下代码:

public class SomeService {

    private Dependency dependency;

    @Transactional(readOnly=false)
    public void doSomething() {
        //some BL code...

        dependency.doSomeDbManipualation();

        someOperation();
    }

    public void someOperation() {
        //some code that eventually fails
    }
}

public class Dependency {

    public void doSomeDbManipulation() {
        Entity entity = ...; //get the entity from current session by its key
        if (entity != null) {
            session.delete(entity);
        }

        OtherEntity oEntity = new OtherEntity();
        //set its fields
        Long oEntityId = session.save(oEntity);

        entity = new Entity();
        entity.setForeignKey(oEntityId);
        //set other fields
        session.persist(entity);
    }
}

现在,我在数据库中有一个具有相关键的实体。所以我希望在调用服务时,查找实体的代码确实会找到它。但由于someOperation() 失败,我预计数据库不会发生任何变化。

事实上,在调用someService.doSomething()(失败)之后,我查看了数据库,发现现有实体已被删除!但是没有创建新实体(没关系)。

为什么这个事务“半提交”?

编辑: 显然 delete() 和 save() 立即提交。当我调试时,我看到在代码中的这一行完成后,该实体被立即删除。 OtherEntity 也会立即添加到数据库中。 persist() 不会立即提交。

我使用 AspectJ 进行事务管理。这是我的 pom.xml 中的相关部分:

<project>
    ...
    <dependencies>
        ...
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>
        ...
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.7</version>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>1.8.3</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <showWeaveInfo>true</showWeaveInfo>
                    <outxml>true</outxml>
                    <forceAjcCompile>true</forceAjcCompile>
                    <source>1.8</source>
                    <target>1.8</target>
                    <Xlint>ignore</Xlint>
                    <complianceLevel>1.8</complianceLevel>
                    <encoding>UTF-8</encoding>
                    <verbose>true</verbose>
                    <preserveAllLocals>true</preserveAllLocals>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-aspects</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                </configuration>
                <executions>
                    <execution>
                        <id>AspectJ-Compile</id>
                        <phase>process-classes</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        ...
    </build>
</project>

【问题讨论】:

  • 如果您在doSomeDbManipulation() 的末尾加上session.flush();,有什么变化吗?事务回滚可能仅针对某些特定类型的异常发生。
  • 可能session.delete(entity); 刷新(并自动提交?)会话,而save()persist() 不会flush()
  • 但是,之前打开的事务在 doSomething 函数中已经提交是没有意义的。对吗?如果是这样的话......事务性注释背后的想法是什么?
  • 这里好像和flush()没有关系,因为问题是我看到变化太早了,而不是预期的时候没看到。不过谢谢。

标签: java hibernate aspectj


【解决方案1】:

我不知道为什么aspect j被显式添加为pom文件中的依赖项。如果您使用spring boot,您将获得开箱即用的方面。当类路径中存在重复的jar时,我看到了不可预知的行为。

我也无法理解为什么从一个本身被标记为只读事务的方法调用数据库操作方法。

我觉得这里的设计不正确。

【讨论】:

  • 对不起,我的错误,您是否尝试过仅使用 spring boot 依赖项删除。也无需在 @Transactional 中指定 readonly = false,默认行为是 readonly =false。
  • 如果我没记错的话,spring boot方面只能应用于接口中可用的方法,而AspectJ更灵活。前段时间是一位同事做出这个决定,所以我不确定我是否记得正确,但我认为这是基本原理。
【解决方案2】:

我找到了问题的解决方案。 我在几个类中有多个 @ComponentScan 注释。当我将它们全部删除并只留下一个时,一切都按预期工作。

我不明白这种奇怪行为的原因,所以我发布了一个单独的问题,here

【讨论】:

    猜你喜欢
    • 2018-05-06
    • 2011-04-05
    • 2013-05-04
    • 2019-09-22
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 2015-02-09
    • 2016-03-19
    相关资源
    最近更新 更多