【问题标题】:SqlException using database populator with Hibernate and Spring data JPASqlException 使用带有 Hibernate 和 Spring 数据 JPA 的数据库填充器
【发布时间】:2017-08-03 15:20:56
【问题描述】:

我试图在加载应用程序期间通过 DatabasePopulator 将数据存储到 mysql 数据库中。我正在使用 Spring MVC、Hibernate 和 Spring Data JPA。但是我得到了一些 SqlException 错误。我一直在尝试通过 Hibernate 提供的更改 ID 生成策略来修复它,但没有成功。 提前致谢。也许需要更改我的域对象对象中的某些内容。如果我手动填充代码一切正常。但是,通过使用 DataPopulator 会遇到错误。

领域对象

 package springmvc.java.domain;

    import java.util.List;

    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;

    @Entity
    @Table(name = "user")
    public class User {

        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        // @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id", unique = true, nullable = false)
        private Long id;

        @Column(name = "username", nullable = false)
        private String username;

        @Column(name = "password")
        private String password;

        @Column(name = "enabled", nullable = false)
        private boolean enabled;

        // @ElementCollection
        @OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
        private List<BlogPost> blogPosts;

        public User() {

        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }

        public List<BlogPost> getBlogPosts() {
            return blogPosts;
        }

        public void setBlogPosts(List<BlogPost> blogPosts) {
            this.blogPosts = blogPosts;
        }

    }




    package springmvc.java.domain;

import java.util.Date;

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


    @Entity
    @Table(name = "blog_post")
    public class BlogPost {

        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name = "id", unique = true, nullable = false)
        private Long id;

        @Column(name = "title", nullable = false)
        private String title;

        @Column(name = "content", nullable = false)
        private String content;

        // @Column(name = "publishDate", nullable = false)
        @Column(name = "publishDate", nullable = true)
        private Date publishDate;

        @Column(name = "draft", nullable = false)
        private boolean draft;

    //  @JsonIgnore
        @ManyToOne
        @JoinColumn(name = "user_id", nullable = false)
        private User user;

        public User getUser() {
            return user;
        }

        public void setUser(User user) {
            this.user = user;
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }

        public Date getPublishDate() {
            return publishDate;
        }

        public void setPublishDate(Date publishDate) {
            this.publishDate = publishDate;
        }

        public boolean isDraft() {
            return draft;
        }

        public void setDraft(boolean draft) {
            this.draft = draft;
        }

    }




package springmvc.java.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

    @Entity
    @Table(name = "authorities")
    public class Authority {

        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name = "", unique = true, nullable = false)
        private Long id;

        @Column(name = "username", nullable = false)
        private String username;

        @Column(name = "authority", nullable = false)
        private String authority;

        public Authority() {

        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getAuthority() {
            return authority;
        }

        public void setAuthority(String authority) {
            this.authority = authority;
        }

    }




package springmvc.java.config;

@EnableJpaRepositories(basePackages = { "springmvc.java.dao" })
@EnableTransactionManagement
@Configuration
@ComponentScan("springmvc.java")
public class ApplicationContext {


    private DatabasePopulator databasePopulator() {

        ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
        databasePopulator.setContinueOnError(false);
        databasePopulator.addScript(new ClassPathResource("/test-insert-data.sql"));

        return databasePopulator;
    }



    /*
     * Second Configuration Option
     * 
     */
    @Bean
    public DataSource getMySQLDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/blog?useSSl=false");
        dataSource.setUsername("root");
        dataSource.setPassword("root");

        return dataSource;
    }



    @Bean
    public BlogPostService blogPostService() {
        return new BlogPostServiceImpl();
    }


    @Bean
    public JpaVendorAdapter getJpaVendorAdapter() {
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setDatabase(Database.MYSQL);
        jpaVendorAdapter.setShowSql(true);

        return jpaVendorAdapter;
    }

    /*
     * Hibernate Configuration
     */
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();

        entityManagerFactory.setDataSource(getMySQLDataSource());

        entityManagerFactory.setJpaVendorAdapter(getJpaVendorAdapter());

        entityManagerFactory.setPackagesToScan("springmvc.java.domain");

        Properties jpaProperties = new Properties();
        jpaProperties.setProperty("hibernate.hbm2ddl.auto", "create-drop");

        entityManagerFactory.setJpaProperties(jpaProperties);

        return entityManagerFactory;
    }

    /*
     * TransactionManager Configuration
     */
    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {

        JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
        jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);

        // The exception is thrown here
        DatabasePopulatorUtils.execute(databasePopulator(), getMySQLDataSource());

        return jpaTransactionManager;
    }
}

返回

错误:

    ERROR ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in springmvc.java.config.ApplicationContext: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaTransactionManager]: Factory method 'transactionManager' threw exception; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [test-insert-data.sql]: INSERT INTO USER(USERNAME, PASSWORD, ENABLED) VALUES('user','password', TRUE); nested exception is java.sql.SQLException: Field 'id' doesn't have a default value
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:443) ~[spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:325) ~[spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107) [spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4725) [catalina.jar:na]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5189) [catalina.jar:na]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:na]
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:752) [catalina.jar:na]
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:728) [catalina.jar:na]
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734) [catalina.jar:na]
    at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:596) [catalina.jar:8.5.9-dev]
    at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1805) [catalina.jar:8.5.9-dev]
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [na:1.8.0_144]
    at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.8.0_144]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_144]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_144]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0_144]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaTransactionManager]: Factory method 'transactionManager' threw exception; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [test-insert-data.sql]: INSERT INTO USER(USERNAME, PASSWORD, ENABLED) VALUES('user','password', TRUE); nested exception is java.sql.SQLException: Field 'id' doesn't have a default value
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    ... 27 common frames omitted
Caused by: org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [test-insert-data.sql]: INSERT INTO USER(USERNAME, PASSWORD, ENABLED) VALUES('user','password', TRUE); nested exception is java.sql.SQLException: Field 'id' doesn't have a default value
    at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:491) ~[spring-jdbc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:238) ~[spring-jdbc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:48) ~[spring-jdbc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at springmvc.java.config.ApplicationContext.transactionManager(ApplicationContext.java:186) ~[classes/:na]
    at springmvc.java.config.ApplicationContext$$EnhancerBySpringCGLIB$$75c8c2da.CGLIB$transactionManager$2(<generated>) ~[classes/:na]
    at springmvc.java.config.ApplicationContext$$EnhancerBySpringCGLIB$$75c8c2da$$FastClassBySpringCGLIB$$9644c818.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:358) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at springmvc.java.config.ApplicationContext$$EnhancerBySpringCGLIB$$75c8c2da.transactionManager(<generated>) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_144]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_144]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_144]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_144]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    ... 28 common frames omitted
Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964) ~[mysql-connector-java-5.1.43.jar:5.1.43]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3973) ~[mysql-connector-java-5.1.43.jar:5.1.43]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3909) ~[mysql-connector-java-5.1.43.jar:5.1.43]
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2527) ~[mysql-connector-java-5.1.43.jar:5.1.43]
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2680) ~[mysql-connector-java-5.1.43.jar:5.1.43]
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2490) ~[mysql-connector-java-5.1.43.jar:5.1.43]
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2448) ~[mysql-connector-java-5.1.43.jar:5.1.43]
    at com.mysql.jdbc.StatementImpl.executeInternal(StatementImpl.java:845) ~[mysql-connector-java-5.1.43.jar:5.1.43]
    at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:745) ~[mysql-connector-java-5.1.43.jar:5.1.43]
    at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:470) ~[spring-jdbc-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    ... 41 common frames omitted

【问题讨论】:

  • 任何提示?真的很感激
  • 我已经编辑了代码。我需要更改或修复什么?
  • 更新您的数据库并将USER 表中的ID 设为AUTO INCREMENT
  • Abdullah Khan,数据库是由 Hibernate 创建的。您可以看到所有字段都已注释。 GenerationType.AUTO 正在执行 AUTO INCREMENT,对吗?如果我错了,请纠正我。有没有其他方法可以使 id 自动递增,而不是手动递增?
  • GenerationType.AUTO 本身不会为您创建数据库和 ID。 hibernate 属性hbm2ddl 为您完成了这项工作。

标签: hibernate spring-mvc spring-data-jpa


【解决方案1】:

失败的可能性有很多,有时可能不会反映任何实体修改。您应该手动删除并重新创建数据库,或者创建新架构并导出现有数据库。

除此之外,您还可以使用 hibernate import_files 属性来加载 sql 脚本:

hibernate.hbm2ddl.import_files=location_of_sqlfiles_comma_saperated_string'. These statements are only executed if the schema is created ie if hibernate.hbm2ddl.auto is set to create or create-drop.

另一个原因是生成类型:

看看 GeneratedValue 的策略。它通常应该看起来像:

@GeneratedValue(strategy=GenerationType.IDENTITY).

您应该使用如下所示的数据库初始化:

@Bean
public DataSourceInitializer dataSourceInitializer(final DataSource dataSource) {
    final DataSourceInitializer initializer = new DataSourceInitializer();
    initializer.setDataSource(dataSource);
    initializer.setDatabasePopulator(databasePopulator());
    return initializer;
}

private DatabasePopulator databasePopulator() {
    final ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
    populator.addScript(schemaScript);
    populator.addScript(dataScript);
    return populator;
}

确保使用自动增量检查创建数据库表

【讨论】:

    【解决方案2】:

    错误很明显:Field 'id' doesn't have a default value

    事实上,您正在尝试使用 SQL 脚本填充数据库。由于您的脚本是通过与数据源的连接直接执行的,因此不使用 Hibernate 来生成 id 的列。

    您需要在 SQL 脚本中添加 id 的值才能使其正常工作。或者您必须使用 Hibernate 填充数据库。在您的情况下,这意味着您可以使用 Spring Data 来完成这项工作。

    【讨论】:

    • victor gallet,我在 SQl 中添加了 id 的值,但出现以下错误:
    • 引起:org.springframework.jdbc.datasource.init.ScriptStatementFailedException:无法执行类路径资源[test-insert-data.sql]的SQL脚本语句#5:INSERT INTO AUTHORITIES(ID ,USERNAME, AUTHORITY) VALUES(1,'user','ROLE_USER')
    • victor gallet,您能否提供一个示例或提示如何使用 Spring Data 填充列?
    • 能否提供完整的异常堆栈跟踪信息?
    猜你喜欢
    • 2014-01-10
    • 2020-07-10
    • 1970-01-01
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    • 2017-07-11
    • 2015-11-26
    • 1970-01-01
    相关资源
    最近更新 更多