Java JPA中的事务回滚永远不起作用

Java JPA中的事务回滚永远不起作用,java,mysql,jpa,transactions,Java,Mysql,Jpa,Transactions,我有一段示例代码: public class JpaTest { private EntityManagerFactory emf; private void setUp() throws Exception { emf = Persistence.createEntityManagerFactory("testPU"); } private void tearDown() { emf.close(); } p

我有一段示例代码:

public class JpaTest {
    private EntityManagerFactory emf;

    private void setUp() throws Exception {
        emf = Persistence.createEntityManagerFactory("testPU");
    }

    private void tearDown() {
        emf.close();
    }

    private void save() {
        EntityManager em = null;
        EntityTransaction tx = null;
        try {
            em = emf.createEntityManager();
            tx = em.getTransaction();
            tx.begin();
            em.persist(new Event("First event", new Date()));
            em.persist(new Event("A follow up event", new Date()));
            throw new RuntimeException();
        } catch (Exception e) {
            if (tx != null) tx.rollback();
        } finally {
            if (em != null) em.close();
        }
    }

    public static void main(String[] args) throws Exception {
        JpaTest test = new JpaTest();
        test.setUp();
        test.save();
        test.tearDown();
    }
}
数据库是MySQL。 代码将事件实体持久化到数据库中,然后引发异常。我希望tx.rollback()删除对数据库所做的更改,但此命令永远不会起作用,数据仍保留在表中:

问题是为什么tx.rollback()失败,以及如果事务引发异常,如何删除在数据库中所做的更改

更新: persistence.xml:

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">

    <persistence-unit name="testPU">

        <class>exampleForTestingJpa.Event</class>

        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url"
                      value="url here..."/>
            <property name="javax.persistence.jdbc.user" value="username here..."/>
            <property name="javax.persistence.jdbc.password" value="password here..."/>

            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.connection.autocommit" value="false"/>
        </properties>
    </persistence-unit>
</persistence>

测试JPA.Event的示例
pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>groupId</groupId>
    <artifactId>example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.3.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.2.9.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.39</version>
        </dependency>
    </dependencies>

</project>

4.0.0
groupId
例子
1.0-快照
maven编译器插件
3.1
1.8
1.8
org.springframework
春季甲虫
4.3.8.1发布
org.hibernate
冬眠核心
5.2.9.最终版本
mysql
mysql连接器java
5.1.39

正如其他用户所说,这可能是一个自动提交问题,因为根据:

在InnoDB中。。。 默认情况下,MySQL为每个新连接启动会话 启用了自动提交,因此,如果 该语句没有返回错误。如果语句返回 错误,提交或回滚行为取决于错误。看见 第14.21.4节,“InnoDB错误处理”

此外,不应将
事务
对象存储在变量中。
每次要调用
事务
方法时,从
EntityManager
获取
事务
对象

因此,请替换:

tx = em.getTransaction();
tx.begin();
作者:

并替换
tx.rollback()
by
em.getTransaction().rollback()

存储在
EntityManager
中的
Transaction
对象可能会被序列化,因此在事务处理期间会有一个新的引用

例如,查看
AbstractEntityManagerImpl
的序列化方法:

public class org.hibernate.jpa.spi.AbstractEntityManagerImpl{
...
  private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    tx = new TransactionImpl( this );
  }
...
}

正如其他用户所说,这可能是一个自动提交问题,因为根据:

在InnoDB中。。。 默认情况下,MySQL为每个新连接启动会话 启用了自动提交,因此,如果 该语句没有返回错误。如果语句返回 错误,提交或回滚行为取决于错误。看见 第14.21.4节,“InnoDB错误处理”

此外,不应将
事务
对象存储在变量中。
每次要调用
事务
方法时,从
EntityManager
获取
事务
对象

因此,请替换:

tx = em.getTransaction();
tx.begin();
作者:

并替换
tx.rollback()
by
em.getTransaction().rollback()

存储在
EntityManager
中的
Transaction
对象可能会被序列化,因此在事务处理期间会有一个新的引用

例如,查看
AbstractEntityManagerImpl
的序列化方法:

public class org.hibernate.jpa.spi.AbstractEntityManagerImpl{
...
  private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    tx = new TransactionImpl( this );
  }
...
}

将其添加到persistence.xml中

<property name="hibernate.connection.autocommit" value="false"/>

将其添加到persistence.xml中

<property name="hibernate.connection.autocommit" value="false"/>

是否启用了自动提交?MySQL手册声明默认情况下启用自动提交


如果这就是问题所在,你肯定不会是第一个在这个问题上绊倒的人;-)

是否启用了自动提交?MySQL手册声明默认情况下启用自动提交



如果这就是问题所在,你肯定不会是第一个在这个问题上绊倒的人;-)

不回滚事务的问题是由MyISAM引起的。InnoDB回滚工作正常。

不回滚事务的问题是由MyISAM引起的。InnoDB回滚工作正常。

fg78nc在mefg78nc之前就有了,我有问题了。在
finally
块中的
commit
怎么样?我认为你也需要它,如果你的JPA提供者真的没有回滚一个事务(并且你没有一些奇怪的配置导致这个),那么这就是你的JPA提供者中的一个bug。默认情况下,任何JPA提供商都不应启用“自动提交”,因为这将违反JPA specTry重建项目的规定。请出示您的pom.xml文件fg78nc,见上文我有一个问题。在
finally
块中的
commit
怎么样?我认为你也需要它,如果你的JPA提供者真的没有回滚一个事务(并且你没有一些奇怪的配置导致这个),那么这就是你的JPA提供者中的一个bug。默认情况下,任何JPA提供商都不应启用“自动提交”,因为这将违反JPA specTry重建项目的规定。请展示您的pom.xml文件fg78nc,参见上文。好吧,查阅手册是我最容易忘记的事情,呵呵。但这里我们给出了一些很好的例子,结果是一样的,但事实并非如此help@sva605你每次尝试都会插入新数据吗?是的,它在回滚时会被插入,而不会被删除。嗯,查阅手册是我最容易忘记的事情,呵呵。但这里我们给出了一些很好的例子,结果是一样的,但事实并非如此help@sva605每次尝试都会插入新数据吗?是的,它会在回滚时插入,而不会被删除。我做了这些替换并插入到persistence.xml中,但没有任何帮助。数据仍然保留在DB表中,回滚无效您是否也使用
em.getTransaction()
进行了修改?我做了这些替换并插入到persistence.xml中,但没有任何帮助。数据仍保留在DB表中,回滚无效您是否也使用
em.getTransaction()
进行了修改?