Spring, Hibernate и JPA: вызов сохраняется в entitymanager, похоже, не фиксируется в базе данных

Я пытаюсь настроить Spring с помощью Hibernate и JPA, но при попытке сохранить объект в базу данных ничего не добавляется.

Я использую следующее:

<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;

Есть ли кто-нибудь, кто может указать на то, что я делаю не так? Вызов persist возвращается без исключения исключений. Если после этого я сделаю em.contains(ac), это вернет истину.

Если кому-то понадобится, вот как определяется 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;
    }
}

Привет, Рубен, я делаю нечто подобное, но у меня есть файл persistence.xml, у тебя он есть, почему или почему нет? Благодарность

bmw0128 15.07.2009 20:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
19
1
53 837
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вероятно, вы сохраняете транзакцию активной, и она не вызывает «фиксацию» до тех пор, пока не будут запущены другие методы, поддерживающие активный конец транзакции (все «голосование» за фиксацию и ни одно за откат).

Если вы уверены, что объект, который вы собираетесь сохранить, в порядке, вы, вероятно, могли бы сделать это:

@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;
}

@TransactionManagement - это EJB.

James McMahon 24.04.2009 19:20
Ответ принят как подходящий

Благодаря ответам Эрика и Хуана Мануэля я смог выяснить, что транзакция не была совершена.

Добавление @Transactional к методу storeAccount помогло!

Это все, что вы сделали, чтобы решить проблему?

James McMahon 24.04.2009 19:51

В моем случае мне пришлось добавить @Transactional в точку входа моего класса. Раньше у меня был только @Transactional в моем методе, который сохранялся. Не уверен, что полностью понимаю, что там происходит.

James McMahon 24.04.2009 22:32

Спасибо, ты тоже спас мне день!

merveotesi 12.01.2012 18:43

Работает! ... кажется, что когда @Transactional добавляется к определенному методу, он автоматически определяет этапы транзакции (начало, фиксация, сброс и т. д.)

Kermit_ice_tea 20.10.2014 05:58

Вам не нужно явно вызывать метод persist. Операция слияния запишет изменения в БД при фиксации.

На самом деле я наткнулся на другой способ, которым это может произойти.

Во внедренном EntityManager никаких обновлений не произойдет, если вы укажете файл persistence.xml следующим образом:

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

Вам нужно удалить атрибут типа транзакции и просто использовать значение по умолчанию - JTA.

После 6 часов стука головой нашел вот это.

panther 11.12.2013 15:35

Другие вопросы по теме