@SequenceGenerator 在保存标识符后不能为空!当 id 的值未传入 h2 时抛出
2020-06-21
2180
我在使用 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 ;
这是 data.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;
我已经尝试了 @GeneratedValue 的其他几个方法
@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)
2个回答
您添加了许多不需要的依赖项。当您添加不需要的依赖项时,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);
}
- 您的 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);
}
...
-
删除
schema.sql
,因为它有错误,JPA 可以自动创建它。 -
应用程序属性
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
Kavithakaran Kanapathippillai
2020-06-21
我相信您需要向存储库接口添加@Repository注释。
Steven Song
2024-02-16