【问题标题】:How to persist when using Spring Boot with JPA将 Spring Boot 与 JPA 一起使用时如何持久化
【发布时间】:2023-03-18 13:38:01
【问题描述】:

我习惯于使用 Spring Roo 来生成我的实体并让它通过 AspectJ 类处理注入 entityManager 以及 persist 和其他方法。 现在我正在尝试使用 Spring Boot 做一些简单的事情,将内容写入数据库......

@Entity
@Table(name = "account")
public class Account { 

  transient EntityManager entityManager;

  @Id
  @GeneratedValue
  private Long id;

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

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

  ... getters and setters

  @Transactional
  public void persist() {
    if (this.entityManager == null) this.entityManager = entityManager();
    this.entityManager.persist(this);
  }

  @Transactional
  public Account merge() {
    if (this.entityManager == null) this.entityManager = entityManager();
    Account merged = this.entityManager.merge(this);
    this.entityManager.flush();
    return merged;
  }

当我调用persist 或merge 时,entityManager 显然为null。

我还尝试将implements CrudRepository<Account, Long> 添加到Account 类中,以查看它会通过默认实现为我提供该功能,但我得到的只是需要填写的空类。

我查看了 Spring Boot 文档,他们非常简要地介绍了它,省略了足够的细节,因此我遗漏了什么并不明显。

我有一个引导应用程序的应用程序类:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

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

}

我的属性文件如下所示:

spring.application.name: Test Application

spring.datasource.url: jdbc:mysql://localhost/test
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

由于ddl-auto=update 属性,此数据库会自动创建

在 Spring Boot + JPA 中持久化实体的正确方法是什么?如果到目前为止我所做的是正确的,我该如何“自动装配”或自动创建 entityManager?

【问题讨论】:

    标签: java spring jpa spring-boot spring-data


    【解决方案1】:

    在您的示例中,您的 EntityManager 始终为空。 Spring 不会自动将一个连接到您的 Entity 类中。我也不确定你的目标是什么,但我敢打赌你很可能不想让你的Entity 持有你的EntityManager

    我认为您可能正在寻找的是Spring Data Repositories。我建议您阅读以了解基础知识。

    开始使用存储库:

    我要做的第一件事是从 Account 类中删除 transient EntityManager entityManager;persist/merge 函数。

    Application 类中,您可以添加 @EnableJpaRepositories 注释。

    接下来创建一个新的Interface(不是新类),这将是您的Account 存储库。

    @Repository
    public interface AccountRepository extends PagingAndSortingRepository<Account, Long>
    

    其中AccountEntity 的类型,LongAccount 的ID 类型

    Spring Data 中包含一些具有各种支持的存储库接口,它们继承自 Repository

    无需向您的界面添加任何内容,PagingAndSortingRepository 将为您提供 CRUD 操作和分页支持。

    还可以使用 JPQL 向您的界面添加自定义查询,请查看 @Query 注释。 http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query

    现在,您可以 @Autowire AccountRepository 进入您的任何 Spring 托管 bean 并开始保存和获取数据。

    【讨论】:

    • 哇,这与 Spring Roo 的做法相比有很大不同,但与所有生成的 AspectJ 文件相比也更简洁。感谢您提供非常详细的答案!
    • Roo 基于 Active Record 模式,实体可以在其中管理自己。 Spring Data 基于 Repository 模式,其中一个单独的对象负责管理域对象。
    【解决方案2】:

    尝试替换:

    @Configuration
    @ComponentScan
    @EnableAutoConfiguration
    

    与:

    @SpringBootApplication
    

    看到这个article

    具体来说:默认情况下,Spring Boot 将启用 JPA 存储库支持,并在 @SpringBootApplication 所在的包(及其子包)中查找。如果您的配置有位于不可见包中的 JPA 存储库接口定义,您可以使用 @EnableJpaRepositories 及其类型安全的 basePackageClasses=MyRepository.class 参数指出备用包。

    【讨论】:

    【解决方案3】:

    您的代码中的问题是:

    1. EntityManager 条目不是 @Autowired,即使它是 @Entity 也不会被识别为 spring bean,因此 spring 的依赖注入服务不起作用
    2. 因为我之前说过,使用@Entity 注释的 bean 不是 Spring bean,因此您无法从 @Transactional 注释中受益

    在这种情况下,您可以使用 Spring DataJPA 项目,记住使用 @EnableJpaRepositories 配置 tis,或者您可以创建存储库以这种方式组织您的代码

    实体:

    @Entity
    @Table(name = "account")
    public class Account { 
    
      @Id
      @GeneratedValue
      private Long id;
    
      @Column(name = "username", nullable = false, unique = true)
      private String username;
    
      @Column(name = "password", nullable = false)
      private String password;
    .... 
    

    }

    存储层:

    public interface AccountRepository {
       void persist();
       Account merge();
    }
    
    @Repository
    class AccountRepositoryJpaImpl implements AccountRepository {
    
      @Autowired
      private EntityManager entityManager;
    
      ...
      @Transactional
      public void persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.persist(this);
      }
    
      @Transactional
      public Account merge() {
        if (this.entityManager == null) this.entityManager = entityManager();
        Account merged = this.entityManager.merge(this);
        this.entityManager.flush();
        return merged;
      }
    ....
    }
    

    @SpringBootApplication 受益于 Spring Boot 的所有功能 @EnableTransactionManagement 有利于事务管理

    @SpringBootApplication
    @EnableTransactionManagement
    class ApplicationConfig {
    
        public static void main(String[] args) {
            SpringApplication.run(ApplicationConfig .class, args);
        }
    }
    

    我希望这可以帮助你。 (拼写更正 2018-02-24)

    【讨论】:

      猜你喜欢
      • 2020-02-07
      • 2020-07-09
      • 1970-01-01
      • 2012-11-29
      • 1970-01-01
      • 2015-03-14
      • 1970-01-01
      • 2014-10-21
      • 2019-07-17
      相关资源
      最近更新 更多