HibernateとJPAを使用してSpringをセットアップしようとしていますが、オブジェクトを永続化しようとすると、データベースに何も追加されていないようです。
以下を使用しています:
_<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" />
_
そして、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;
}
}
_
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;
_
私が間違っていることを指摘できる人はいますか?永続呼び出しは、例外をスローせずに戻ります。その後、em.contains(ac)
を実行すると、trueが返されます。
誰かが必要な場合に備えて、アカウントの定義方法は次のとおりです。
_@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;
}
}
_
EricとJuanManuelの回答のおかげで、トランザクションがコミットされていないことがわかりました。
StoreAccountメソッドに@Transactionalを追加すると、うまくいきました。
私は実際にこれが起こり得る別の方法に出くわしました。
挿入されたEntityManagerでは、次のようにpersistence.xmlが指定されている場合、更新は発生しません。
<persistence-unit name="primary" transaction-type="RESOURCE_LOCAL">
トランザクションタイプ属性を削除し、デフォルトのJTAを使用する必要があります。
明示的にpersistメソッドを呼び出す必要はありません。マージ操作は、コミット時に変更をDBに書き込みます。
おそらく、トランザクションをアクティブに保ち、アクティブなトランザクションをサポートする実行中の他のメソッドが終了するまで「コミット」を呼び出しません(すべてコミットに「投票」し、ロールバックには投票しません)。
永続化するエンティティに問題がないことが確実な場合は、おそらく次のようにすることができます。
@TransactionManagement(TransactionManagementType.BEAN)
public class AccountManager implements IAccountManager { ..}
以下を追加して、エンティティの永続性を管理します。
@Resource
private SessionContext sessionContext;
public Account storeAccount(Account ac) {
sessionContext.getUserTransaction().begin();
ac = em.merge(ac);
em.persist(ac);
sessionContext.getUserTransaction().commit();
return ac;
}