JPA 事务未提交给数据库

Posted

技术标签:

【中文标题】JPA 事务未提交给数据库【英文标题】:JPA Transaction not committed to DB 【发布时间】:2012-05-22 18:36:52 【问题描述】:

我正在做一个小型 Spring-Hibernate-mysql 测试项目,由于某种原因,我的事务没有提交到数据库。

在我的应用程序上下文中,我得到了:

<!-- JTA -->

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />

</bean>

<tx:annotation-driven transaction-manager="txManager" />

<!-- JPA -->

<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/myPU" />

<!-- In order to enable EntityManager injection -->
<bean
    class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
    <property name="persistenceUnits">
        <map>
            <entry key="myPU" value="persistence/myPU" />
        </map>
    </property>
</bean>

我的persistence.xml:

<persistence-unit name="myPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/mysqlResource</jta-data-source>
    <properties>
        <property name="hibernate.connection.shutdown" value="true" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"></property>
        <property name="hibernate.show_sql" value="true" />
    </properties>
</persistence-unit>

我在我的数据库中创建了一个名为“persons”的简单表:

CREATE TABLE persons(
id VARCHAR(255) PRIMARY KEY,
version int, 
full_name VARCHAR(255),
person_id VARCHAR(255),
email VARCHAR(255));

创建实体一个对应的实体和道:

@Entity
@Table(name = "persons")
public class Person implements Serializable 

private static final long serialVersionUID = 4349832844316517922L;

/*--- Members ---*/

/**
 * Hibernate genetared UUID
 */
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;

@Version
private int version;

@Column(name = "full_name")
private String fullName;

@Column(name = "person_id")
private String personId;

@Column(name = "email")
private String eMail;

/*--- Constructor ---*/

public Person() 


/*--- Overridden Methods ---*/

@Override
public boolean equals(Object obj) 

    if ((obj == null) || !(obj instanceof Person)) 
        return false;
    

    // reference comparison
    if (obj == this) 
        return true;
    

    final Person other = (Person) obj;

    return new EqualsBuilder().append(getPersonId(), other.getPersonId())
            .append(geteMail(), other.geteMail())
            .append(getFullName(), other.getFullName()).isEquals();


/**
 * The unique hash code based on the clients' id and citizenship
 * 
 * @inheritDoc
 */
@Override
public int hashCode() 

    return new HashCodeBuilder().append(geteMail()).append(this.geteMail())
            .append(this.getFullName()).toHashCode();


/*--- Getters & Setters ---*/

public String getId() 
    return id;


public void setId(String id) 
    this.id = id;


public int getVersion() 
    return version;


public void setVersion(int version) 
    this.version = version;


public String getFullName() 
    return fullName;


public void setFullName(String fullName) 
    this.fullName = fullName;


public String getPersonId() 
    return personId;


public void setPersonId(String personId) 
    this.personId = personId;


public String geteMail() 
    return eMail;


public void seteMail(String eMail) 
    this.eMail = eMail;

道:

@Repository
public class PersonJpaDao extends BasicJpaDao<Person> implements IPersonDao 

public PersonJpaDao() 
    super(Person.class);

这里是 BasicJpaDao:

public class BasicJpaDao<T> implements IBasicDao<T> 

/* --- Members --- */

/** The JPA utility to work with the persistence layer. */
@PersistenceContext
protected EntityManager entityManager;

/** The type of the entity to which this DAO offers access. */
protected Class<T> entityClass;

/* --- Constructors --- */

/**
 * Default constructor.
 * 
 * @param entityClass
 *            The type of the entity to which this DAO offers access.
 */
public BasicJpaDao(Class<T> entityClass) 
    super();
    this.entityClass = entityClass;


/* --- Public methods --- */

/**
 * @inheritDoc
 */
@Override
public void create(T entity) 
    getEntityManager().persist(entity);


/**
 * @inheritDoc
 */
@Override
public T read(Object primaryKey) 
    return getEntityManager().find(getEntityClass(), primaryKey);


/**
 * @inheritDoc
 */
@Override
public T update(T entity) 
    return getEntityManager().merge(entity);


/**
 * @inheritDoc
 */
@Override
public void delete(T entity) 
    getEntityManager().remove(entity);


/**
 * @inheritDoc
 */
@Override
public void flush() 
    getEntityManager().flush();


/* --- Getters/Setters --- */

/**
 * @return The JPA utility to work with the persistence layer.
 */
public EntityManager getEntityManager() 
    return this.entityManager;


/**
 * @param entityManager
 *            The JPA utility to work with the persistence layer.
 */
public void setEntityManager(EntityManager entityManager) 
    this.entityManager = entityManager;


/**
 * @return The type of the entity to which this DAO offers access.
 */
public Class<T> getEntityClass() 
    return entityClass;


/**
 * @param entityClass
 *            The type of the entity to which this DAO offers access.
 */
public void setEntityClass(Class<T> entityClass) 
    this.entityClass = entityClass;

Soo.. 基本上它可以工作,但没有任何承诺,我的意思是,如果我运行

@Transactional(propagation = Propagation.REQUIRED)
private void crearePerson() 
    Person p1 = myDao.read("12345");
    p1.setFullName("kiko too");
    myDao.update(p1);

我可以看到(在调试中)p1 从数据库中返回,但从未发生更新。 我能找到的唯一接近的是:

JPA - transactions not being committed

我尝试添加

<property name="hibernate.connection.shutdown" value="true" />

到我的persistence.xml 跟随这个线程,但它没有帮助。 我还向我的连接池(在我的应用程序服务器 gui 中)添加了一个名为 connection.shutdown 的属性,其值为 true,但它也没有帮助。

更新: 由于我使用的是 JTA,我认为我的事务管理器配置错误。当我使用 org.springframework.orm.jpa.JpaTransactionManager 时,我应该使用 org.springframework.transaction.jta.JtaTransactionManager。 所以我改变了我的应用程序上下文,现在我有了:

<bean id="txManager"
    class="org.springframework.transaction.jta.JtaTransactionManager" />

<tx:annotation-driven transaction-manager="txManager" />

很遗憾,我仍然遇到同样的问题 :( 在我的控制台中,我可以看到休眠查询如下()我已经更改了一些原始实体字段,但这并不重要):

INFO: Hibernate: select user0_.id as id0_0_, user0_.email as email0_0_, user0_.full_name as full3_0_0_, user0_.password as password0_0_, user0_.update_by_email as update5_0_0_, user0_.user_name as user6_0_0_, user0_.version as version0_0_ from用户 user0_ where user0_.id=?

有什么想法吗?

提前致谢, 修行者

【问题讨论】:

【参考方案1】:

它可能不起作用的原因是因为您在私有方法上使用了@Transactional@Transactional 对非公共方法没有影响,因为代理生成器会忽略它们。来自Spring Documentation:

方法可见性和@Transactional

当使用代理时,你应该应用@Transactional注解 仅适用于具有公共可见性的方法。如果您确实注释受保护, 带有 @Transactional 注释的私有或包可见方法, 没有引发错误,但带注释的方法没有表现出 配置的事务设置。考虑使用 AspectJ(参见 下面)如果您需要注释非公共方法。

【讨论】:

谢谢!但是更改方法的可见性并没有帮助,此外,我认为由于我的类(包含 crearePerson 方法的类)实现了一个未定义 crearePerson 方法的接口,因此 spring 将无法使用事务注释。所以,我尝试了两种不同的方法,第一种将方法声明添加到接口 - 仍然无法正常工作。其次,添加 cglig 并声明 以便spring忽略该接口。这也没有帮助。我在这里迷路了..【参考方案2】:

我遇到了类似的问题,对我来说,解决方法来自以下:

在 PersistenceXML 中:

<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup">

弹簧文件:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="nameOfUnitInPersistenceXml" />
</bean>

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManagerName" value="java:/TransactionManager" />
</bean>

Java 类(命名持久化上下文)

private EntityManager em;

@PersistenceContext(name="nameOfUnitInPersistenceXml")
public void setEntityManager(EntityManager em) 
    this.em = em;

【讨论】:

【参考方案3】:

将“@Transactional”添加到您的 create() 方法中。

编辑:最好将@Transactional 放在服务层而不是dao 层,仅供参考

【讨论】:

嗨,谢谢。我确实在交易中运行,只是编辑了我的问题。运行代码后仍然看不到我的表得到更新,我当然同意 - @Transactional 注释通常应该发生在业务逻辑层

以上是关于JPA 事务未提交给数据库的主要内容,如果未能解决你的问题,请参考以下文章

Spring data JPA:未提交每条记录的事务

spring spring data jpa save操作事务

无法提交 JPA 事务:事务标记为 rollbackOnly

事务未在春季批处理项目编写器中回滚

重新整理 mysql 基础篇————— 事务隔离级别[四]

Spring JPA无法提交jdbc事务的解决办法