Spring + Hibernate没有在DB中插入(@Transactional not work)

时间:2017-06-28 03:07:20

标签: java spring hibernate spring-mvc jpa

这是我在Stackoverflow中的第一个问题。

Spring JPA Hibernate存在很大问题。 我可以读取表格(通过我的实体中定义的@NamedQuery选择),但我无法将实体持久存储到数据库中。

我正在使用: - 春季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;
    }

}

实体:

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")

})     公共类GameUser实现了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;
    }
}

存储库:

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

}

服务:

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

日志:

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

Execution image

当我执行单元测试时,它成功完成(不是异常或日志错误)。但是当我看到桌子时,桌子上没有新记录。

Hibernate的日志不显示INSERT语句。

有什么想法吗?我读了很多而没找到解决方案:(

4 个答案:

答案 0 :(得分:1)

我更改了EntityManagerFactory的注入:

@Autowired
private EntityManagerFactory entityManagerFactory;

....
this.entityManagerFactory.getEntityManager();
....

标准JPA:

@PersistenceContext
private EntityManager entityManager;

完美无缺:3

答案 1 :(得分:0)

坚持后可以尝试冲洗吗?

@Override
@Transactional
public void create(GameUser gameUser) {
 this.gameUserRepository.create(gameUser);
 this.getEntityManager().flush(); 
   }

答案 2 :(得分:0)

如果您没有收到任何错误,那么您的事务管理器似乎配置不正确,并且不会向您的数据库发送任何提交。

hidePred = [NSPredicate predicateWithFormat:@"hide != %@", [NSNumber numberWithBool:YES]]

还有一件事需要检查:确保@Transactional注释来自包org.springframework.transaction.annotation,而不是javax.transaction

答案 3 :(得分:0)

测试完成后,您在表格中看不到任何内容,因为SpringJUnit4ClassRunner会自动回滚。