将 Spring Boot 与 JPA 一起使用时如何持久化
Posted
技术标签:
【中文标题】将 Spring Boot 与 JPA 一起使用时如何持久化【英文标题】:How to persist when using Spring Boot with JPA 【发布时间】:2016-06-25 21:56:16 【问题描述】:我习惯于使用 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?
【问题讨论】:
【参考方案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>
其中Account
是Entity
的类型,Long
是Account
的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 参数指出备用包。
【讨论】:
@SpringBootApplication
只是为了方便添加,相当于添加了@Configuration, @ComponentScan, @EnableAutoConfiguration
。 docs.spring.io/spring-boot/docs/current/reference/html/…【参考方案3】:
您的代码中的问题是:
-
EntityManager 条目不是 @Autowired,即使它是 @Entity 也不会被识别为 spring bean,因此 spring 的依赖注入服务不起作用
因为我之前说过,使用@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)
【讨论】:
以上是关于将 Spring Boot 与 JPA 一起使用时如何持久化的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 自动配置无法与 spring-data-jpa 一起正常工作
Spring Boot + Spring Batch + Spring JPA
JPA 左连接查询不会在 Spring Boot 中实例化子集合?
Spring Boot JPA CrudRepository 选择性更新 - 只有一些属性