Я пытаюсь настроить 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;
}
}




Вероятно, вы сохраняете транзакцию активной, и она не вызывает «фиксацию» до тех пор, пока не будут запущены другие методы, поддерживающие активный конец транзакции (все «голосование» за фиксацию и ни одно за откат).
Если вы уверены, что объект, который вы собираетесь сохранить, в порядке, вы, вероятно, могли бы сделать это:
@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.
Благодаря ответам Эрика и Хуана Мануэля я смог выяснить, что транзакция не была совершена.
Добавление @Transactional к методу storeAccount помогло!
Это все, что вы сделали, чтобы решить проблему?
В моем случае мне пришлось добавить @Transactional в точку входа моего класса. Раньше у меня был только @Transactional в моем методе, который сохранялся. Не уверен, что полностью понимаю, что там происходит.
Спасибо, ты тоже спас мне день!
Работает! ... кажется, что когда @Transactional добавляется к определенному методу, он автоматически определяет этапы транзакции (начало, фиксация, сброс и т. д.)
Вам не нужно явно вызывать метод persist. Операция слияния запишет изменения в БД при фиксации.
На самом деле я наткнулся на другой способ, которым это может произойти.
Во внедренном EntityManager никаких обновлений не произойдет, если вы укажете файл persistence.xml следующим образом:
<persistence-unit name = "primary" transaction-type = "RESOURCE_LOCAL">
Вам нужно удалить атрибут типа транзакции и просто использовать значение по умолчанию - JTA.
После 6 часов стука головой нашел вот это.
Привет, Рубен, я делаю нечто подобное, но у меня есть файл persistence.xml, у тебя он есть, почему или почему нет? Благодарность