EntityTransaction永远不会回滚,抛出异常,说事务处于非活动状态

时间:2011-11-18 12:44:15

标签: jpa

我正在研究使用JPA进行对象持久化的java的独立应用程序,而提供程序是Hibernate。现在,当我持久化实体并调用EntityTransaction的commit()时,实体将持久保存到数据库。如果约束等存在数据库错误,则存在异常,当我尝试回滚时,我得到一个java.lang.IllegalStateException。什么都没有得到承诺。

我有一个Role实体,它使用表生成策略为该实体生成主键。每当提交失败并且下次保存角色时,为先前保存生成的序列将丢失,并且这次是递增的。此问题也会持续存在于自动增量策略中。使用hibernate SessionFactory时,我没有遇到这个问题。

代码:

Role.java

    @Entity
    @Table(schema="System")
    public class Role extends PrincipalEntityBase{

    @TableGenerator(schema="System",table="MasterSequence", valueColumnName="Sequence",
        pkColumnName="GenKey",pkColumnValue="Role_ID",
        name="System.Role", allocationSize=0)
@Id
@GeneratedValue(generator="System.Role",strategy=GenerationType.TABLE)
@Column(name="Role_ID")
private Long role_ID;

@Column(name="RoleName")
private String roleName;

    public Role() {
    }

public Long getRole_ID() {
    return this.role_ID;
}

public void setRole_ID(Long role_ID) {
    this.role_ID = role_ID;
}

public String getRoleName() {
    return this.roleName;
}

public void setRoleName(String roleName) {
    this.roleName = roleName;
}
}

Main.java

    public static void main(String[] args){
            Role r = new Role();
    r.setRoleName("Hello");
    EntityManager em = persistence.createEntityManagerFactory("test")
            .createEntityManager();
    EntityTransaction tr = em.getTransaction();
    try {
        tr.begin();
        em.persist(r);
        tr.commit();
    } catch (Exception e) {
        e.printStackTrace();
        tr.rollback();
        System.out.println("Rolled back");
    }
    }

StackTrace:

    javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:93)
at com.mis.jpa.test.main.Main.main(Main.java:32)
    Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert: [com.mis.entity.system.Role]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1235)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:81)
... 1 more
    Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.mis.entity.system.Role]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)

    Exception in thread "main" java.lang.IllegalStateException: Transaction not active
at org.hibernate.ejb.TransactionImpl.rollback(TransactionImpl.java:104)
at com.mis.jpa.test.main.Main.main(Main.java:35)

Db服务器是MSSQL服务器。

Persistence.xml

    <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <class>com.mis.entity.system.Role</class>

    <properties>

        <!-- Connection properties -->
        <property name="javax.persistence.jdbc.driver"
            value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
        <property name="javax.persistence.jdbc.url"             value="jdbc:sqlserver://192.168.1.2:1433;databaseName=jparesearch" />
        <property name="javax.persistence.jdbc.user" value="sa" />
        <property name="javax.persistence.jdbc.password" value="admin" />

        <!-- JPA Provider Settings -->
        <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" />
        <property name="hibernate.hbm2ddl.auto" value="update" />
        <property name="hibernate.show_sql" value="true" />
      </properties>
</persistence-unit>

1 个答案:

答案 0 :(得分:4)

第一个问题:为什么回滚失败。回滚失败,因为它不是在抛出异常的提交之前的某些代码,而是提交本身。如果commit抛出RollbackException,则表示提交失败,因此将提交转换为回滚并使事务处于非活动状态。只需在回滚事务之前测试事务是否处于活动状态。

第二个问题:为什么生成的ID序列中存在漏洞。当被要求提供新ID时,生成器会在其自身的短期事务中递增序列号。因此,如果您的事务回滚并因此不使用生成的ID,则序列中将存在漏洞,因为表中的增量已经提交。如果它没有使用它自己的短期事务,那么,要么你会有很多冲突(因为几个长事务会看到相同的当前值并且稍后才增加它),或者吞吐量会非常低,因为所有想要ID的交易必须等待先前的交易完成。

洞是不可避免的。处理它们。