Reputation: 35
It's my first question in Stackoverflow.
I have a big problem with Spring JPA Hibernate. I can read tables (select via @NamedQuery defined in my entities), but I cannot persists entities into db.
I'm using: - Spring 4.3.9 - Hibernate 5.2.10
WebConfig:
package cl.duoc.loteria.config;
import java.util.Locale;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.format.FormatterRegistry;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;
@Configuration
@EnableTransactionManagement
@ComponentScan("cl.duoc.loteria.*")
@EnableWebMvc
@PropertySource(value = { "classpath:application.properties" })
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
private Environment environment;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Bean
public InternalResourceViewResolver jspViewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setPrefix("/WEB-INF/views/");
bean.setSuffix(".jsp");
return bean;
}
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions(new String[] { "/WEB-INF/tiles/tiles.xml" });
tilesConfigurer.setCheckRefresh(true);
return tilesConfigurer;
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
TilesViewResolver viewResolver = new TilesViewResolver();
registry.viewResolver(viewResolver);
}
@Bean(name = "messageSource")
public ReloadableResourceBundleMessageSource getMessageSource() {
ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
resource.setBasename("classpath:messages");
resource.setDefaultEncoding("UTF-8");
return resource;
}
@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
cookieLocaleResolver.setDefaultLocale(new Locale("es"));
return cookieLocaleResolver;
}
@Override
public void addFormatters(FormatterRegistry registry) {
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setPackagesToScan(new String[] { "cl.duoc.loteria.entity" });
entityManagerFactory.setJpaProperties(additionalProperties());
entityManagerFactory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return entityManagerFactory;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
return jpaTransactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties additionalProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
// properties.put("hibernate.current_session_context_class",
// environment.getProperty("hibernate.current_session_context_class"));
return properties;
}
}
Entity:
package cl.duoc.loteria.entity;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
/**
*
* @author Waroz
*/
@Entity
@Table(name = "game_user", catalog = "loteria", schema = "")
@NamedQueries({
@NamedQuery(name = "GameUser.findAll", query = "SELECT g FROM GameUser g")
, @NamedQuery(name = "GameUser.findById", query = "SELECT g FROM GameUser g WHERE g.id = :id")
, @NamedQuery(name = "GameUser.findByUserId", query = "SELECT g FROM GameUser g WHERE g.user.id = :userId")
}) public class GameUser implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Basic(optional = false)
@NotNull
@Column(name = "number_1")
private int number1;
@Basic(optional = false)
@NotNull
@Column(name = "number_2")
private int number2;
@Basic(optional = false)
@NotNull
@Column(name = "number_3")
private int number3;
@Basic(optional = false)
@NotNull
@Column(name = "number_4")
private int number4;
@Basic(optional = false)
@NotNull
@Column(name = "number_5")
private int number5;
@Basic(optional = false)
@NotNull
@Column(name = "number_6")
private int number6;
@Basic(optional = false)
@NotNull
@Column(name = "price")
private int price;
@JoinColumn(name = "game_id", referencedColumnName = "id")
@ManyToOne(optional = false)
private Game game;
@JoinColumn(name = "user_id", referencedColumnName = "id")
@ManyToOne(optional = false)
private User user;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "gameUser")
private GameUserReviewed gameUserReviewed;
public GameUser() {
}
public GameUser(Integer id) {
this.id = id;
}
public GameUser(Integer id, int number1, int number2, int number3, int number4, int number5, int number6, int price) {
this.id = id;
this.number1 = number1;
this.number2 = number2;
this.number3 = number3;
this.number4 = number4;
this.number5 = number5;
this.number6 = number6;
this.price = price;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public int getNumber1() {
return number1;
}
public void setNumber1(int number1) {
this.number1 = number1;
}
public int getNumber2() {
return number2;
}
public void setNumber2(int number2) {
this.number2 = number2;
}
public int getNumber3() {
return number3;
}
public void setNumber3(int number3) {
this.number3 = number3;
}
public int getNumber4() {
return number4;
}
public void setNumber4(int number4) {
this.number4 = number4;
}
public int getNumber5() {
return number5;
}
public void setNumber5(int number5) {
this.number5 = number5;
}
public int getNumber6() {
return number6;
}
public void setNumber6(int number6) {
this.number6 = number6;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Game getGame() {
return game;
}
public void setGame(Game game) {
this.game = game;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public GameUserReviewed getGameUserReviewed() {
return gameUserReviewed;
}
public void setGameUserReviewed(GameUserReviewed gameUserReviewed) {
this.gameUserReviewed = gameUserReviewed;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof GameUser)) {
return false;
}
GameUser other = (GameUser) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
}
Repository:
package cl.duoc.loteria.repository;
import java.util.List;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import cl.duoc.loteria.entity.GameUser;
@Repository("gameUserRepository")
public class GameUserRepositoryImpl extends AbstractRepository<Integer, GameUser> implements GameUserRepository {
@Override
public List<GameUser> list() {
List<GameUser> gameUsers = this.getEntityManager().createNamedQuery("GameUser.findAll", GameUser.class)
.getResultList();
return gameUsers;
}
@Override
public List<GameUser> findByUserId(int userId) {
List<GameUser> gameUsers = this.getEntityManager().createNamedQuery("GameUser.findByUserId", GameUser.class)
.setParameter("userId", userId).getResultList();
return gameUsers;
}
@Override
public void create(GameUser gameUser) {
this.getEntityManager().persist(gameUser);
}
@Override
public void delete(GameUser gameUser) {
this.getEntityManager().remove(gameUser);
}
}
Service:
package cl.duoc.loteria.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cl.duoc.loteria.entity.GameUser;
import cl.duoc.loteria.repository.GameUserRepository;
@Service("gameUserService")
public class GameUserServiceImpl implements GameUserService {
@Autowired
private GameUserRepository gameUserRepository;
@Override
public List<GameUser> findByUserId(int userId) {
List<GameUser> gameUsers = this.gameUserRepository.findByUserId(userId);
return gameUsers;
}
@Override
@Transactional
public void create(GameUser gameUser) {
this.gameUserRepository.create(gameUser);
}
}
Unit test:
package cl.duoc.loteria.service;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import java.util.List;
import static org.hamcrest.Matchers.greaterThan;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import cl.duoc.loteria.config.WebConfig;
import cl.duoc.loteria.entity.GameUser;
import cl.duoc.loteria.repository.GameRepository;
import cl.duoc.loteria.repository.UserRepository;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = WebConfig.class)
@WebAppConfiguration
public class GameUserServiceTest {
@Autowired
private GameUserService gameUserService;
@Autowired
private GameRepository gameRepository;
@Autowired
private UserRepository userRepository;
@Test
public void contextLoadsTest() {
assertThat(this.gameUserService, notNullValue());
}
@Test
public void findByUserId() {
List<GameUser> gameUsers = this.gameUserService.findByUserId(1);
assertThat(gameUsers.size(), greaterThan(0));
}
@Test
public void createTest() {
GameUser gameUser = new GameUser();
gameUser.setGame(this.gameRepository.findById(1));
gameUser.setUser(this.userRepository.findById(1));
gameUser.setNumber1(22);
gameUser.setNumber2(44);
gameUser.setNumber3(55);
gameUser.setNumber4(66);
gameUser.setNumber5(77);
gameUser.setNumber6(88);
gameUser.setPrice(1200);
this.gameUserService.create(gameUser);
}
}
Log:
DEBUG 2017-06-28 21:51:58,725 [default task-28] org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl - Starting ResultSet row #0
DEBUG 2017-06-28 21:51:58,725 [default task-28] org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl - On call to EntityIdentifierReaderImpl#resolve, EntityKey was already known; should only happen on root returns with an optional identifier specified
DEBUG 2017-06-28 21:51:58,725 [default task-28] org.hibernate.engine.internal.TwoPhaseLoad - Resolving associations for [cl.duoc.loteria.entity.Company#1]
DEBUG 2017-06-28 21:51:58,725 [default task-28] org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [cl.duoc.loteria.entity.Company#1]
DEBUG 2017-06-28 21:51:58,725 [default task-28] org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl - HHH000387: ResultSet's statement was not registered
DEBUG 2017-06-28 21:51:58,725 [default task-28] org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader - Done entity load : cl.duoc.loteria.entity.Company#1
DEBUG 2017-06-28 21:51:58,726 [default task-28] org.hibernate.loader.Loader - Loading entity: [cl.duoc.loteria.entity.GameFinished#3]
DEBUG 2017-06-28 21:51:58,726 [default task-28] org.hibernate.SQL -
select
gamefinish0_.id as id1_2_2_,
gamefinish0_.game_id as game_id8_2_2_,
gamefinish0_.number_1 as number_2_2_2_,
gamefinish0_.number_2 as number_3_2_2_,
gamefinish0_.number_3 as number_4_2_2_,
gamefinish0_.number_4 as number_5_2_2_,
gamefinish0_.number_5 as number_6_2_2_,
gamefinish0_.number_6 as number_7_2_2_,
game1_.id as id1_1_0_,
game1_.company_id as company_3_1_0_,
game1_.game_date as game_dat2_1_0_,
company2_.id as id1_0_1_,
company2_.funds as funds2_0_1_,
company2_.name as name3_0_1_
from
loteria.game_finished gamefinish0_
inner join
loteria.game game1_
on gamefinish0_.game_id=game1_.id
left outer join
loteria.company company2_
on game1_.company_id=company2_.id
where
gamefinish0_.game_id=?
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - Hibernate:
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - select
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - gamefinish0_.id as id1_2_2_,
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - gamefinish0_.game_id as game_id8_2_2_,
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - gamefinish0_.number_1 as number_2_2_2_,
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - gamefinish0_.number_2 as number_3_2_2_,
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - gamefinish0_.number_3 as number_4_2_2_,
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - gamefinish0_.number_4 as number_5_2_2_,
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - gamefinish0_.number_5 as number_6_2_2_,
INFO 2017-06-28 21:51:58,726 [default task-28] stdout - gamefinish0_.number_6 as number_7_2_2_,
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - game1_.id as id1_1_0_,
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - game1_.company_id as company_3_1_0_,
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - game1_.game_date as game_dat2_1_0_,
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - company2_.id as id1_0_1_,
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - company2_.funds as funds2_0_1_,
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - company2_.name as name3_0_1_
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - from
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - loteria.game_finished gamefinish0_
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - inner join
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - loteria.game game1_
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - on gamefinish0_.game_id=game1_.id
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - left outer join
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - loteria.company company2_
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - on game1_.company_id=company2_.id
INFO 2017-06-28 21:51:58,727 [default task-28] stdout - where
INFO 2017-06-28 21:51:58,728 [default task-28] stdout - gamefinish0_.game_id=?
DEBUG 2017-06-28 21:51:58,728 [default task-28] org.hibernate.loader.Loader - Done entity load
DEBUG 2017-06-28 21:51:58,728 [default task-28] org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [cl.duoc.loteria.entity.Game#3]
DEBUG 2017-06-28 21:51:58,728 [default task-28] org.springframework.orm.jpa.JpaTransactionManager - Creating new transaction with name [cl.duoc.loteria.service.GameUserServiceImpl.create]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG 2017-06-28 21:51:58,728 [default task-28] org.springframework.orm.jpa.JpaTransactionManager - Opened new EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for JPA transaction
DEBUG 2017-06-28 21:51:58,728 [default task-28] org.hibernate.engine.transaction.internal.TransactionImpl - begin
DEBUG 2017-06-28 21:51:58,729 [default task-28] org.springframework.jdbc.datasource.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost:3306/loteria]
DEBUG 2017-06-28 21:51:58,733 [default task-28] org.springframework.orm.jpa.JpaTransactionManager - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@1ee91cde]
DEBUG 2017-06-28 21:51:58,733 [default task-28] org.springframework.orm.jpa.JpaTransactionManager - Initiating transaction commit
DEBUG 2017-06-28 21:51:58,733 [default task-28] org.springframework.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
DEBUG 2017-06-28 21:51:58,733 [default task-28] org.hibernate.engine.transaction.internal.TransactionImpl - committing
DEBUG 2017-06-28 21:51:58,733 [default task-28] org.springframework.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
DEBUG 2017-06-28 21:51:58,733 [default task-28] org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
When I execute my unit test, it finished successfully (not exception or log errors). But when I see the table, the table hasn't new records.
The Hibernate's log doesn't show an INSERT statement.
Any ideas? I read a lot and not found solution :(
Upvotes: 1
Views: 3097
Reputation: 35
I changed the injection of EntityManagerFactory:
@Autowired
private EntityManagerFactory entityManagerFactory;
....
this.entityManagerFactory.getEntityManager();
....
To standar JPA:
@PersistenceContext
private EntityManager entityManager;
And works perfectly :3
Upvotes: 1
Reputation: 3134
You see nothing in table after tests finish because SpringJUnit4ClassRunner
does automatic rolback.
Upvotes: 0
Reputation: 7624
If you get no error, it seems your transaction Manager is not correct configured and sends no commit to your database.
@Transactional
public void create(GameUser gameUser) {
this.gameUserRepository.create(gameUser);
}
One more thing to check: Be sure, @Transactional annotation is from package org.springframework.transaction.annotation, not javax.transaction
Upvotes: 0
Reputation: 52
Can you try flush after persisting.
@Override
@Transactional
public void create(GameUser gameUser) {
this.gameUserRepository.create(gameUser);
this.getEntityManager().flush();
}
Upvotes: 0