@SequenceGenerator 抛出 保存后标识符不能为空!当h2中没有传入id的值时

问题描述 投票:0回答:2

我在使用序列时将 spring boot 与 h2 数据库结合使用,并且使用 @SequenceGenerator 似乎没有生成主键的值。我想默认生成Id的值,然后将值更新到数据库中。 这是我的课程的详细信息。

CardHolder.java

package com.spring.book.rental.dao.model;

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

@Entity
@Table(name = "card_holder")
public class CardHolder {

    @Id
    @Column
      @GeneratedValue(generator="SEQ_CARD_HOLDER_ID",strategy=GenerationType.IDENTITY)
      @SequenceGenerator(name="SEQ_CARD_HOLDER_ID",
      sequenceName="SEQ_PG_CARD_HOLDER_ID",initialValue = 1)
    public int id;

    @Column(name = "last_name")
    public String lastName;

    @Column(name = "first_name")
    public String firstName;

    @Column(name = "card_number")
    public String cardNumber;

    public int getId() {
        return id;
    }

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

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getCardNumber() {
        return cardNumber;
    }

    public void setCardNumber(String cardNumber) {
        this.cardNumber = cardNumber;
    }
}

BookController.java

package com.spring.book.rental.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.spring.book.rental.DTO.BookDTO;
import com.spring.book.rental.DTO.RentBookRequest;
import com.spring.book.rental.service.BookService;

@RestController
public class BookController {

    @Autowired
    BookService bookService;
    
    @PostMapping(path="book-rental/rentABook", consumes = "application/json")
    public String rentABook(@RequestBody RentBookRequest bookRequest) {
        try {
            bookService.rentBook(bookRequest);
            return "You rented a Book Id : "+bookRequest.getBookId();
        } catch (Exception e) {
            return e.getMessage();
        }
    }
    
}

BookServiceImpl.java

package com.spring.book.rental.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.spring.book.rental.DTO.BookDTO;
import com.spring.book.rental.DTO.RentBookRequest;
import com.spring.book.rental.dao.BookDAO;
import com.spring.book.rental.dao.CardHolderDAO;
import com.spring.book.rental.dao.RentalDAO;
import com.spring.book.rental.dao.model.Book;
import com.spring.book.rental.dao.model.CardHolder;
import com.spring.book.rental.dao.model.Rental;
import com.spring.book.rental.service.BookService;

@Service("bookService")
@Component
public class BookServiceImpl implements BookService {

    @Autowired
    BookDAO bookDao;
    
    @Autowired
    CardHolderDAO cardHolderDAO;
    
    @Autowired
    RentalDAO rentalDAO;

    @Override
    public void rentBook(RentBookRequest bookRequest) throws Exception {
                    
        CardHolder cardHolder = new CardHolder();
        cardHolder.setFirstName(bookRequest.getFirstName());
        cardHolder.setLastName(bookRequest.getLastName());
        cardHolder.setCardNumber(bookRequest.getCardNumber());
        cardHolderDAO.addCardHolder(cardHolder);
        
        /* Rental rental = new Rental();
        rental.setBook_id(bookRequest.getBookId());
        rental.setCardHolder_id(cardHolder.getId());
        rentalDAO.addRental(rental); */
        
    }

}

CardHolderDAOImpl.java

package com.spring.book.rental.dao.impl;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.spring.book.rental.dao.CardHolderDAO;
import com.spring.book.rental.dao.model.CardHolder;
import com.spring.book.rental.dao.repository.CardHolderRepository;

@Repository
public class CardHolderDAOImpl implements CardHolderDAO {

    @Autowired
    CardHolderRepository cardHolderRepository;
    
    @Override
    public void addCardHolder(CardHolder cardHolder) {
        cardHolderRepository.save(cardHolder);
    }
    
}

CardHolderRepository.java

package com.spring.book.rental.dao.repository;

import java.util.Optional;

import org.springframework.data.repository.CrudRepository;

import com.spring.book.rental.dao.model.CardHolder;

public interface CardHolderRepository extends CrudRepository<CardHolder, Integer> {

    public Optional<CardHolder> findById(Integer id);
}

RentBookRequest.java

package com.spring.book.rental.DTO;

public class RentBookRequest {

    private int bookId;
    
    private int cardHolderId;
    
    private String firstName;
    
    private String lastName;
    
    private String cardNumber;

    public int getBookId() {
        return bookId;
    }

    public void setBookId(int bookId) {
        this.bookId = bookId;
    }

    public int getCardHolderId() {
        return cardHolderId;
    }

    public void setCardHolderId(int cardHolderId) {
        this.cardHolderId = cardHolderId;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getCardNumber() {
        return cardNumber;
    }

    public void setCardNumber(String cardNumber) {
        this.cardNumber = cardNumber;
    }
    
}

这是主课

SpringTaskBookRentalApplication.java

package com.spring.book.rental;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

import sun.misc.Contended;

@ComponentScan(basePackages = "com")
@EnableAutoConfiguration
@SpringBootApplication
public class SpringTaskBookRentalApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringTaskBookRentalApplication.class, args);
    }

}

我已将其添加到 application.properties 文件中

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:bookrentaldb
spring.datasource.username=admin
spring.datasource.password=admin
spring.h2.console.enabled=true
spring.h2.console.path=/h2

spring.datasource.continue-on-error=false
spring.datasource.initialize=true
spring.datasource.separator=;
spring.datasource.sql-script-encoding=UTF-8

这是 schema.sql 文件

create table BOOK(
    id int not null primary key,
    title varchar(50) not null,
    IS_BOOK_AVAILABLE boolean not null,
    author varchar(50) not null,
    primary key(id)
);

create table card_holder (
    id int not null primary key AUTO_INCREMENT,
    first_name varchar(20),
    last_name varchar(20),
    card_number varchar(20),
    primary key(id)
);

create table Rental(
    rental_id int not null primary key AUTO_INCREMENT,
    cardHolder_id int not null,
    book_id int not null
);

 CREATE SEQUENCE SEQ_PG_CARD_HOLDER_ID  MINVALUE 1 MAXVALUE 9999 INCREMENT BY 1 START WITH 1  NOCYCLE ;
 
 CREATE SEQUENCE SEQ_PG_Rental_ID  MINVALUE 1 MAXVALUE 999999 INCREMENT BY 1 START WITH 100   NOCYCLE ;

这是数据.sql

insert into BOOK (id,title,IS_BOOK_AVAILABLE,author) values (101,'A Thousand Splendid Suns','true','Khalid Hosseini');

insert into BOOK (id,title,IS_BOOK_AVAILABLE,author) values (102,'Head First Design Patterns','true','Elisabeth Freeman and Kathy Sierra');

insert into BOOK (id,title,IS_BOOK_AVAILABLE,author) values (103,'Head First Java','true','Book by Bert Bates and Kathy Sierra');

commit;

我已经用@GenerateValue尝试了其他一些事情

@Id
    @Column
    @GeneratedValue(strategy=GenerationType.AUTO)
    public int id;

这是我收到的错误的 stackTrace

java.lang.IllegalArgumentException: After saving the identifier must not be null!
    at org.springframework.util.Assert.notNull(Assert.java:198)
    at org.springframework.data.jdbc.core.JdbcAggregateTemplate.store(JdbcAggregateTemplate.java:343)
    at org.springframework.data.jdbc.core.JdbcAggregateTemplate.save(JdbcAggregateTemplate.java:149)
    at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.save(SimpleJdbcRepository.java:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.data.repository.core.support.ImplementationInvocationMetadata.invoke(ImplementationInvocationMetadata.java:72)
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:382)
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:205)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:549)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:155)
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:130)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy81.save(Unknown Source)
    at com.spring.book.rental.dao.impl.CardHolderDAOImpl.addCardHolder(CardHolderDAOImpl.java:38)
    at com.spring.book.rental.dao.impl.CardHolderDAOImpl$$FastClassBySpringCGLIB$$8e01a85d.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
    at com.spring.book.rental.dao.impl.CardHolderDAOImpl$$EnhancerBySpringCGLIB$$5a6f1054.addCardHolder(<generated>)
    at com.spring.book.rental.service.impl.BookServiceImpl.rentBook(BookServiceImpl.java:68)
    at com.spring.book.rental.controller.BookController.rentABook(BookController.java:29)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
java spring-boot spring-data-jpa h2
2个回答
1
投票

您添加了很多不需要的依赖项。当您添加不需要的依赖项时,Spring Boot 会尝试猜测您的应用程序的类型并进行相应的配置。

我还建议阅读 Spring data JPA 与 Spring Data JDBC,因为两者是混合的。

1.

    public CardHolder addCardHolder(CardHolder cardHolder) {
        return cardHolderRepository.save(cardHolder);
    }
    @Override
    public void rentBook(RentBookRequest bookRequest) throws Exception {
                    
        CardHolder cardHolder = new CardHolder();
        cardHolder.setFirstName(bookRequest.getFirstName());
        cardHolder.setLastName(bookRequest.getLastName());
        cardHolder.setCardNumber(bookRequest.getCardNumber());
        CardHolder saved = cardHolderDAO.addCardHolder(cardHolder);
        
        Rental rental = new Rental();
        rental.setBook_id(bookRequest.getBookId());
        rental.setCardHolder_id(saved.getId());
        rentalDAO.addRental(rental); 
        
    }
  1. 您的 pom 应该仅包含以下内容。您当前正在添加许多不同的依赖项
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

package com.spring.book.rental.dao.model;

import javax.persistence.*;

@Entity
@Table(name = "BOOK")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public int id;
    
    @Column
    public String title;

    @Column(name = "IS_BOOK_AVAILABLE")
    public boolean isBookAvailable;
    
    @Column
    public String author;
...
package com.spring.book.rental.dao.model;

import javax.persistence.*;

@Entity
@Table(name = "card_holder")
public class CardHolder {

    @Id
     @GeneratedValue(generator="SEQ_CARD_HOLDER_ID",strategy=GenerationType.IDENTITY)
    @SequenceGenerator(name="SEQ_CARD_HOLDER_ID", sequenceName="SEQ_PG_CARD_HOLDER_ID",initialValue = 1)
    @Column
    public int id;

    @Column(name = "last_name")
    public String lastName;

    @Column(name = "first_name")
    public String firstName;

    @Column(name = "card_number")
    public String cardNumber;
....
package com.spring.book.rental.dao.model;

import javax.persistence.*;

import org.springframework.boot.autoconfigure.domain.EntityScan;

@Entity
@Table(name = "Rental")
public class Rental {

    @Id
    @Column(name = "rental_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    public int rentalId;

    @Column(name = "cardHolder_id")
    public int cardHolder_id;

    @Column(name = "book_id")
    public int book_id;
....
package com.spring.book.rental.dao.repository;

import com.spring.book.rental.dao.model.Book;
import org.springframework.data.repository.CrudRepository;

import java.util.List;
import java.util.Optional;

public interface BookRepository extends CrudRepository<Book,Integer>{

    public List<Book> findAllByIsBookAvailableTrue();
    
    public List<Book> findAll();
    
    public Optional<Book> findById(Integer id);
}
...
  1. 删除

    schema.sql
    ,因为它有错误,JPA 可以自动创建它。

  2. 应用程序属性

spring.jpa.show-sql=true 
spring.jpa.properties.hibernate.format_sql=true 
logging.level.org.hibernate.SQL=DEBUG 
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

0
投票

我认为您需要在存储库接口中添加@Repository注释。

© www.soinside.com 2019 - 2024. All rights reserved.