Java Spring、Hibernate 和 JPA:在 entitymanager 上调用持久化似乎没有提交到数据库
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/374886/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring, Hibernate & JPA: Calling persist on entitymanager does not seem to commit to database
提问by Ruben Vermeersch
I'm trying to setup Spring using Hibernate and JPA, but when trying to persist an object, nothing seems to be added to the database.
我正在尝试使用 Hibernate 和 JPA 设置 Spring,但是当尝试持久化对象时,似乎没有向数据库添加任何内容。
Am using the following:
我正在使用以下内容:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="BankingWeb" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
<property name="databasePlatform" value="${hibernate.dialect}" />
</bean>
</property>
</bean>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean name="accountManager" class="ssel.banking.dao.jpa.AccountManager" />
<bean name="userManager" class="ssel.banking.dao.jpa.UserManager" />
And in AccountManager, I'm doing:
在 AccountManager 中,我正在做:
@Repository
public class AccountManager implements IAccountManager {
@PersistenceContext private EntityManager em;
/* -- 8< -- Query methods omitted -- 8< -- */
public Account storeAccount(Account ac) {
ac = em.merge(ac);
em.persist(ac);
return ac;
}
}
Where ac comes from:
ac 来自哪里:
Account ac = new Account();
ac.setId(mostRecent.getId()+1);
ac.setUser(user);
ac.setName(accName);
ac.setDate(new Date());
ac.setValue(0);
ac = accountManager.storeAccount(ac);
return ac;
Is there anyone who can point out what I'm doing wrong? The persist call returns without throwing exceptions. If afterwards I do em.contains(ac)
, this returns true.
有没有人可以指出我做错了什么?持久调用返回而不抛出异常。如果之后我这样做em.contains(ac)
,这将返回true。
In case anyone needed, here's how Account is defined:
如果有人需要,以下是 Account 的定义方式:
@SuppressWarnings("serial")
@Entity
@NamedQueries({
@NamedQuery(name = "Account.AllAccounts", query = "SELECT a FROM Account a"),
@NamedQuery(name = "Account.Accounts4User", query = "SELECT a FROM Account a WHERE user=:user"),
@NamedQuery(name = "Account.Account4Name", query = "SELECT a FROM Account a WHERE name=:name"),
@NamedQuery(name = "Account.MaxId", query = "SELECT MAX(a.id) FROM Account a"),
@NamedQuery(name = "Account.Account4Id", query = "SELECT a FROM Account a WHERE id=:id"),
})
public class Account extends AbstractNamedDomain {
@Temporal(TemporalType.DATE)
@Column(name = "xdate")
private Date date;
private double value;
@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name="userid")
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE}, fetch=FetchType.EAGER)
@OrderBy("date")
private List<AccountActivity> accountActivity = new ArrayList<AccountActivity>();
public List<AccountActivity> getAccountActivity() {
return accountActivity;
}
public void setAccountActivity(List<AccountActivity> accountActivity) {
this.accountActivity = accountActivity;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public void addAccountActivity(AccountActivity activity) {
// Make sure ordering is maintained, JPA only does this on loading
int i = 0;
while (i < getAccountActivity().size()) {
if (getAccountActivity().get(i).getDate().compareTo(activity.getDate()) <= 0)
break;
i++;
}
getAccountActivity().add(i, activity);
}
}
@MappedSuperclass public abstract class AbstractNamedDomain extends AbstractDomain {
private String name;
public AbstractNamedDomain() {
}
public AbstractNamedDomain(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@MappedSuperclass public abstract class AbstractDomain implements Serializable {
@Id @GeneratedValue
private long id = NEW_ID;
public static long NEW_ID = -1;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public boolean isNew() {
return id==NEW_ID;
}
}
采纳答案by Ruben Vermeersch
Thanks to eric and Juan Manuel's answers, I was able to figure out that the transaction wasn't committed.
多亏了 eric 和 Juan Manuel 的回答,我才知道交易没有提交。
Adding @Transactional to the storeAccount method did the trick!
将 @Transactional 添加到 storeAccount 方法就成功了!
回答by Juan Manuel
Probably you're keeping the transaction active and it is not calling "commit" until other methods running supporting the active transaction end (all "voting" for commit and none for rollback.)
可能您保持事务处于活动状态,并且在其他运行支持活动事务的方法结束之前它不会调用“提交”(所有“投票”用于提交,没有用于回滚。)
If you're sure that the entity you're going to persist is ok you could probably do this:
如果您确定要保留的实体没问题,您可以这样做:
@TransactionManagement(TransactionManagementType.BEAN)
public class AccountManager implements IAccountManager { ..}
and manage your entity persistance adding:
并管理您的实体持久性添加:
@Resource
private SessionContext sessionContext;
public Account storeAccount(Account ac) {
sessionContext.getUserTransaction().begin();
ac = em.merge(ac);
em.persist(ac);
sessionContext.getUserTransaction().commit();
return ac;
}
回答by Ruben Vermeersch
You do not explicitly need to call the persist method. The merge operation would write the changes to the DB upon commit.
您不需要明确调用persist 方法。合并操作会在提交时将更改写入数据库。
回答by Nicholas DiPiazza
I actually came across another way that this can happen.
我实际上遇到了另一种可能发生这种情况的方式。
In an injected EntityManager, no updates will ever occur if you have persistence.xml specified like this:
在注入的 EntityManager 中,如果您像这样指定了persistence.xml,则永远不会发生更新:
<persistence-unit name="primary" transaction-type="RESOURCE_LOCAL">
<persistence-unit name="primary" transaction-type="RESOURCE_LOCAL">
You need to remove the transaction-type attribute and just use the default which is JTA.
您需要删除事务类型属性并仅使用默认值 JTA。