【问题标题】:Why does entity object will be detached, after a method returns it? (Spring data JPA)为什么实体对象在方法返回后会被分离? (弹簧数据JPA)
【发布时间】:2020-06-05 22:00:20
【问题描述】:

已解决:问题出在环绕方面,它以某种方式修改了代理中的返回值。对不起,无法回答的问题。也许有人知道我的错。感谢您提供有用的答案!

我的 Spring Boot 控制台应用程序有问题。我也在使用 spring data jpa 来坚持。一切正常,我可以保存和查找实体,但是当服务类方法返回一个实体时,它将被分离。当我想使用返回的对象时,应用程序失败,因为对象值为空。

这只是一个例子。

@Entity
@Table(name = "person")
public class Person {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private int id;
    private String name;
    @Convert(converter = LocalDateAttributeConverter.class)
    private LocalDate birth;

    public Person() {
    }
    //getter, setter..
}
public interface PersonRepository extends CrudRepository<Person, Long> {

    public Person findByName(String name);

}
public class Service {

    @Autowired
    private PersonRepository personRepository;

    public Person findPersonByName(String name) {
        return personRepository.findByName(name); // System.out.println(person.name) -> someone
    }
}
public class App {

    private Service service;

    public void doSomething(){
        Person person = service.findPersonByName("someone"); 
        // System.out.println(person.name) -> nullpointerEx
    }
} 
//The player like person in the exaple. I must cover some detail in the package names. 
//This is the real exception. As a say above, the code it's just a raw example. Probably don't match for this.
Hibernate: select player0_.id as id1_7_, player0_1_.email as email2_7_, player0_1_.password as password3_7_, player0_.balance as balance1_4_, player0_.birth as birth2_4_, player0_.currency as currency3_4_, player0_.name as name4_4_ from player player0_ inner join user player0_1_ on player0_.id=player0_1_.id where player0_.name=?

14:24:02.087 [main] INFO  o.s.b.a.l.ConditionEvaluationReportLoggingListener - 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
14:24:02.103 [main] ERROR o.s.boot.SpringApplication - Application run failed
java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:787)
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:768)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:322)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
    at com....Application.main(..Application.java:13)
Caused by: java.lang.NullPointerException: null
    at com.....view.ConsoleView.printWelcomeMassege(ConsoleView.java:101)
    at com.....App.createPersone(App.java:46)
    at com.....App.play(App.java:33)
    at com....Application.lambda$0(..Application.java:22)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:784)
    ... 5 common frames omitted
14:24:02.118 [main] INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
14:24:02.118 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
14:24:02.165 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.

我该如何处理?

【问题讨论】:

  • 在PersonRepository接口中,需要添加一个类级别的注解Repository。
  • 你的实体真的持久化在数据库中了吗?你检查了吗?
  • @bubisbuble,您能否通过添加异常详细信息来编辑您的帖子?
  • 您的示例中的App 类是什么,它是控制器吗?如何调用doSomething 方法?
  • 你知道实体分离是什么意思吗?您收到的是 NPE,不要将其与正在分离的实体混为一谈。

标签: java spring hibernate spring-data-jpa entitymanager


【解决方案1】:

我认为您缺少 @Column(name = "name") 注释

【讨论】:

  • 这是不必要的,当没有明确指定时,将应用默认约定来推导出它。
【解决方案2】:

为什么实体对象在方法返回后会被分离?

因为服务未声明为事务性的。

试试:

@Service
**@Transactional**
public class Service {

    @Autowired
    private PersonRepository personRepository;

    public Person findPersonByName(String name) {
        return personRepository.findByName(name); // System.out.println(person.name) -> someone
    }
}

@Service
public class Service {

    @Autowired
    private PersonRepository personRepository;

    **@Transactional**
    public Person findPersonByName(String name) {
        return personRepository.findByName(name); // System.out.println(person.name) -> someone
    }
}

要减少注释的数量并降低忘记注释的风险,您还可以使用自定义注释TransactionalService

**@TransactionalService**
public class Service {

    @Autowired
    private PersonRepository personRepository;

    public Person findPersonByName(String name) {
        return personRepository.findByName(name); // System.out.println(person.name) -> someone
    }
}

TransactionalService 还配置为回滚 BusinessException 及其子类。

Drombler Commons 是开源的,可从 Maven Central 获得:

<dependency>
  <groupId>org.drombler.commons</groupId>
  <artifactId>drombler-commons-spring-transaction</artifactId>
  <version>1.0</version>
</dependency>

但是请注意,分离实体不会使它们为空。 访问 name 属性时你真的得到 NullPointerException 吗?这表明无法找到该实体。

但从您的代码示例看来,您从访问未初始化的服务中获得了 NullPointerException。

您需要在 App 类中自动装配 Service 以消除 NullPointerException:

**// Some spring annotation**
public class App {

    **@Autowired**
    private Service service;

    public void doSomething(){
        Person person = service.findPersonByName("someone"); 
        // System.out.println(person.name) -> nullpointerEx
    }
} 

【讨论】:

  • 我已经尝试过事务和服务注释,但没有效果。我在 appconfig 中处理服务 bean,并在应用程序中设置它。
  • 对不起,我试过了,但它不起作用。我有一些方面是记录每个服务方法调用并且服务运行良好。当我写入服务方法时,SystemOut (Person) 是有效的,它具有我想要的任何属性,但是当我返回这个其他类时它消失了,person 为空。
猜你喜欢
  • 2017-01-04
  • 1970-01-01
  • 2019-03-30
  • 2015-09-10
  • 2021-01-15
  • 2014-03-28
  • 2020-11-11
  • 1970-01-01
  • 2011-06-20
相关资源
最近更新 更多