我尝试将PersonManager及其List存储到数据库中。
实际上一切似乎都顺利,没有错误,PersonManager正确存储在数据库中。但不是它的列表
但是一旦我访问数据库并尝试迭代保存在PersonManager列表中的人员,返回的List总是为空。
我使用Spring-Boot,Hibernate并拥有一个基于H2文件的数据库。日志就在这篇文章的最后,对于了解情况很重要。
此处my Repo
人
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
final String name;
@ManyToOne
private PersonManager personManager;
public PersonManager getPersonManager() {
return personManager;
}
public void setPersonManager(PersonManager personManager) {
this.personManager = personManager;
}
public String getName() {
return name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (!id.equals(person.id)) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
@Override
public int hashCode() {
int result = id.hashCode();
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
public Person(String name) {
this.name = name;
}
}
PersonManager
@Entity
public class PersonManager {
@OneToMany(mappedBy = "personManager", fetch = FetchType.EAGER)
private final List<Person> personList = new LinkedList<>();
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PersonManager that = (PersonManager) o;
if (!id.equals(that.id)) return false;
return personList != null ? personList.equals(that.personList) : that.personList == null;
}
@Override
public int hashCode() {
int result = id.hashCode();
result = 31 * result + (personList != null ? personList.hashCode() : 0);
return result;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<Person> getPersonList() {
return personList;
}
public void addPerson(Person person) {
personList.add(person);
}
public void removePerson(Person person) {
personList.remove(person);
}
}
HibernateApplication
@SpringBootApplication
public class HibernateApplication {
private static final Logger log = LoggerFactory.getLogger(HibernateApplication.class);
public static void main(String[] args) {
SpringApplication.run(HibernateApplication.class);
}
@Bean
public CommandLineRunner addObservables(ObserveableRepository repository) {
return (args) -> {
useObserver(repository);
// fetch all customers
log.info("PersonManager found with findAll():");
log.info("-------------------------------");
for (PersonManager personManager : repository.findAll()) {
log.info("ListContent: " + personManager.getPersonList().size());
}
log.info("");
};
}
private void usePersonManager(PersonManagerRepo repository) {
PersonManager personManager = new PersonManager();
personManager.addPerson(new Person("Hans"));
personManager.addPerson(new Person("Peter"));
personManager.addPerson(new Person("Max"));
log.info("List.size() : " + personManager.getPersonList().size());
repository.save(personManager);
}
/**
* Start internal H2 server so we can query the DB from IDE
*
* @return H2 Server instance
* @throws SQLException
*/
/*
@Bean(initMethod = "start", destroyMethod = "stop")
public Server h2Server() throws SQLException {
return Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092");
}
*/
}
PersonManagerRepo
public interface PersonManagerRepo extends CrudRepository<PersonManager, Long> {
}
application.properties
spring.datasource.url=jdbc:h2:file:~/test2;DB_CLOSE_ON_EXIT=FALSE;AUTO_RECONNECT=TRUE
spring.datasource.username=admin
spring.datasource.password=password
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
我记录了列表的大小和元素,如下所示。在第一次运行时,元素存在。重建后,他们走了。
2017-06-12 17:12:26.160 INFO 3252 --- [ main] c.e.hibernate.HibernateApplication : No active profile set, falling back to default profiles: default
2017-06-12 17:12:26.185 INFO 3252 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4516af24: startup date [Mon Jun 12 17:12:26 CEST 2017]; root of context hierarchy
2017-06-12 17:12:26.948 INFO 3252 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$b98d9ce8] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-06-12 17:12:27.156 INFO 3252 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-06-12 17:12:27.162 INFO 3252 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2017-06-12 17:12:27.163 INFO 3252 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.14
2017-06-12 17:12:27.212 INFO 3252 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-06-12 17:12:27.212 INFO 3252 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1029 ms
2017-06-12 17:12:27.284 INFO 3252 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-06-12 17:12:27.286 INFO 3252 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-06-12 17:12:27.287 INFO 3252 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-06-12 17:12:27.287 INFO 3252 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-06-12 17:12:27.287 INFO 3252 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-06-12 17:12:27.506 INFO 3252 --- [ main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2017-06-12 17:12:27.513 INFO 3252 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2017-06-12 17:12:27.546 INFO 3252 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.0.12.Final}
2017-06-12 17:12:27.546 INFO 3252 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2017-06-12 17:12:27.547 INFO 3252 --- [ main] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist
2017-06-12 17:12:27.567 INFO 3252 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-06-12 17:12:27.619 INFO 3252 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2017-06-12 17:12:27.858 INFO 3252 --- [ main] org.hibernate.tuple.PojoInstantiator : HHH000182: No default (no-argument) constructor for class: com.example.hibernate.Person (class must be instantiated by Interceptor)
2017-06-12 17:12:27.901 INFO 3252 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000227: Running hbm2ddl schema export
Hibernate: drop table person if exists
Hibernate: drop table person_manager if exists
Hibernate: create table person (id bigint generated by default as identity, name varchar(255), person_manager_id bigint, primary key (id))
Hibernate: create table person_manager (id bigint generated by default as identity, primary key (id))
Hibernate: alter table person add constraint FKmyv6vk7htrqtbt7ji7rngwgh2 foreign key (person_manager_id) references person
2017-06-12 17:12:27.912 INFO 3252 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : HHH000230: Schema export complete
2017-06-12 17:12:27.928 INFO 3252 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2017-06-12 17:12:28.173 INFO 3252 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4516af24: startup date [Mon Jun 12 17:12:26 CEST 2017]; root of context hierarchy
2017-06-12 17:12:28.208 INFO 3252 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-06-12 17:12:28.209 INFO 3252 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-06-12 17:12:28.223 INFO 3252 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-06-12 17:12:28.223 INFO 3252 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-06-12 17:12:28.241 INFO 3252 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-06-12 17:12:28.369 INFO 3252 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-06-12 17:12:28.398 INFO 3252 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-06-12 17:12:28.400 INFO 3252 --- [ main] c.e.hibernate.HibernateApplication : List.size() : 3
Hibernate: insert into person_manager (id) values (null)
2017-06-12 17:12:28.434 INFO 3252 --- [ main] c.e.hibernate.HibernateApplication : Observables found with findAll():
2017-06-12 17:12:28.434 INFO 3252 --- [ main] c.e.hibernate.HibernateApplication : -------------------------------
2017-06-12 17:12:28.446 INFO 3252 --- [ main] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select personmana0_.id as id1_1_ from person_manager personmana0_
Hibernate: select personlist0_.person_manager_id as person_m3_0_0_, personlist0_.id as id1_0_0_, personlist0_.id as id1_0_1_, personlist0_.name as name2_0_1_, personlist0_.person_manager_id as person_m3_0_1_ from person personlist0_ where personlist0_.person_manager_id=?
2017-06-12 17:12:28.493 INFO 3252 --- [ main] c.e.hibernate.HibernateApplication : ListContent: 0
2017-06-12 17:12:28.493 INFO 3252 --- [ main] c.e.hibernate.HibernateApplication :
2017-06-12 17:12:28.494 INFO 3252 --- [ main] c.e.hibernate.HibernateApplication : Started HibernateApplication in 2.47 seconds (JVM running for 2.718)
你能告诉我如何解决这个问题吗?
谢谢:)
答案 0 :(得分:1)
这里的关键是你要建立一个双向关系,你想要级联操作。因此,第一个更改是在PersonManager实体上为@OneToMany注释添加级联。
@OneToMany(mappedBy = "personManager", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
然后你需要记住,当你创建新的Child元素时,你需要将它们与它们的父元素相关联。
为了做到这一点,首先向Person实体添加一个新的构造函数:
public Person(String name, PersonManager personManager) {
this.name = name;
this.personManager = personManager;
}
注意您可能还想添加默认的公共构造函数,因此Hibernate不需要使用拦截器。如果您仔细观察日志,则可能会在日志中看到当前实施的警告。
public Person() {
this.name = null;
}
最后更改您的HibernateApplication类。在创建Person对象时,调用新构造函数并传入Parent的实例。您的另一个选择是创建每个Person对象,然后调用setPersonManager方法,为每个对象传递PersonManager实例。
private void useObserver(ObserveableRepository repository) {
PersonManager personManager = new PersonManager();
personManager.addPerson(new Person("Hans", personManager));
personManager.addPerson(new Person("Peter", personManager));
personManager.addPerson(new Person("Max", personManager));
log.info("List.size() : " + personManager.getPersonList().size());
repository.save(personManager);
}