web-dev-qa-db-ja.com

Spring、Hibernate、JPA:entitymanagerでpersistを呼び出すと、データベースにコミットされないようです

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;
    }
}
_
17

EricとJuanManuelの回答のおかげで、トランザクションがコミットされていないことがわかりました。

StoreAccountメソッドに@Transactionalを追加すると、うまくいきました。

18

私は実際にこれが起こり得る別の方法に出くわしました。

挿入されたEntityManagerでは、次のようにpersistence.xmlが指定されている場合、更新は発生しません。

<persistence-unit name="primary" transaction-type="RESOURCE_LOCAL">

トランザクションタイプ属性を削除し、デフォルトのJTAを使用する必要があります。

4

明示的にpersistメソッドを呼び出す必要はありません。マージ操作は、コミット時に変更をDBに書き込みます。

1
Mohnish

おそらく、トランザクションをアクティブに保ち、アクティブなトランザクションをサポートする実行中の他のメソッドが終了するまで「コミット」を呼び出しません(すべてコミットに「投票」し、ロールバックには投票しません)。

永続化するエンティティに問題がないことが確実な場合は、おそらく次のようにすることができます。

@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;
}
1
Juan Manuel