JPA全稱Java Persistence API,能夠經過註解或者XML描述【對象-關係表】之間的映射關係,並將實體對象持久化到數據庫中。JPA的出現主要是爲了簡化持久層開發以及整合ORM技術,結束Hibernate、TopLink、JDO等ORM框架各自爲營的局面。java
JAP爲咱們提供了ORM映射元數據,JPA的API,JPQL查詢語言等,但JPA僅僅是一種規範,也就是說JPA僅僅定義了一些接口,而接口是須要實現才能工做的。因此底層須要某種實現,而Hibernate就是實現了JPA接口的ORM框架。mysql
Hibernate是Java中的對象關係映射解決方案。對象關係映射或ORM是將應用程序域模型對象映射到關係數據庫表的編程技術。Hibernate是一個基於Java的ORM工具,它提供了一個框架,用於將應用程序域對象映射到關係數據庫表。web
Hibernate提供了Java Persistence API的參考實現,使其成爲具備鬆散耦合優點的ORM工具的絕佳選擇。spring
Spring Data是Spring Framework的一部分。Spring Data存儲庫抽象的目標是顯著減小爲各類持久性存儲實現數據訪問層所需的代碼量。sql
Spring Data JPA不是JPA提供者。它是一個庫/框架,它在咱們的JPA提供程序(如Hibernate)的頂部添加了一個額外的抽象層。數據庫
Hibernate是一個JPA實現,而Spring Data JPA是一個JPA數據訪問抽象。Spring Data提供了GenericDao自定義實現的解決方案,它還能夠經過方法名稱約定表明您生成JPA查詢。編程
Spring Data JPA不是一個實現或JPA提供者,它只是一個抽象,用於顯著減小爲各類持久性存儲實現數據訪問層所需的代碼量。Spring Data JPA始終須要JPA提供程序,如Hibernate。bash
JPA Spring Data:致力於減小數據訪問層(DAO)的開發量,開發者惟一要作的,就只是聲明持久層的接口,其餘都交給Spring Data JPA來完成。mybatis
框架怎麼可能代替開發者實現業務邏輯呢?好比:當有一個 UserDao.findUserById() 這樣一個方法聲明,大體應該能判斷出這是根據給定條件的 ID 查詢出知足條件的 User 對象。Spring Data JPA 作的即是規範方法的名字,根據符合規範的名字來肯定方法須要實現什麼樣的邏輯。mvc
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
複製代碼
@Configuration
// 藉助spring data實現自動化的jpa repository,只需編寫接口無需編寫實現類
// 至關於xml配置的<jpa:repositories base-package="com.example.repository" />
// repositoryImplementationPostfix默認就是Impl
// entityManagerFactoryRef默認就是entityManagerFactory
// transactionManagerRef默認就是transactionManager
@EnableJpaRepositories(basePackages = {"com.wtj.repository"},
repositoryImplementationPostfix = "Impl",
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager")
// 啓用事務管理器
@EnableTransactionManagement
//審計功能 用來自動填充@CreateDate等
@EnableJpaAuditing(dateTimeProviderRef = "dateTimeProvider")
public class SpringDataJpaConfig {
@Bean
public DateTimeProvider dateTimeProvider(DateTimeService dateTimeService) {
return dateTimeService::getNow;
}
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
// 設置數據庫類型(可以使用org.springframework.orm.jpa.vendor包下的Database枚舉類)
jpaVendorAdapter.setDatabase(Database.MYSQL);
// 設置打印sql語句
jpaVendorAdapter.setShowSql(true);
// 設置不生成ddl語句
jpaVendorAdapter.setGenerateDdl(false);
// 設置hibernate方言
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQL5Dialect");
return jpaVendorAdapter;
}
// 配置實體管理器工廠
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();
// 注入數據源
emfb.setDataSource(dataSource);
// 注入jpa廠商適配器
emfb.setJpaVendorAdapter(jpaVendorAdapter);
// 設置掃描基本包
emfb.setPackagesToScan("com.wtj.entity");
return emfb;
}
// 配置jpa事務管理器
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
// 配置實體管理器工廠
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
複製代碼
啓用web支持還須要在Spring MVC配置類上添加@EnableSpringDataWebSupport
註解
@Configuration
@ComponentScan(basePackages = {"com.wtj.controller"})
@EnableWebMvc // 啓用spring mvc
@EnableSpringDataWebSupport // 啓用springmvc對spring data的支持
public class WebMvcConfig extends WebMvcConfigurerAdapter {
}
複製代碼
配置文件
server:
port: 20000
servlet:
context-path: /
spring:
datasource:
url: jdbc:mysql://localhost:3306/mytest1?useUnicode=true&serverTimezone=UTC&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false
username: root
password: root
jpa:
database: MySQL
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: update
複製代碼
ddl-auto 解釋:
例子簡單就不寫service層了,直接在controller中調用。
建立實體類
@Data
@Entity
@Table(name = "account")
@ToString
public class Account {
@Id
@GenericGenerator(name = "idGenerator", strategy = "uuid")
@GeneratedValue(generator = "idGenerator")
private String id;
@Column(name = "username", unique = true, nullable = false, length = 64)
private String username;
@Column(name = "password", nullable = false, length = 64)
private String password;
@Column(name = "email", length = 64)
private String email;
}
複製代碼
主鍵採用UUID策略
@GenericGenerator
是Hibernate提供的主鍵生成策略註解,注意下面的@GeneratedValue
(JPA註解)使用generator = "idGenerator"引用了上面的name = "idGenerator"主鍵生成策略。
JPA自帶的幾種主鍵生成策略
TABLE: 使用一個特定的數據庫表格來保存主鍵。
SEQUENCE: 根據底層數據庫的序列來生成主鍵,條件是數據庫支持序列。這個值要與generator一塊兒使用,generator 指定生成主鍵使用的生成器(多是orcale中本身編寫的序列)。
IDENTITY: 主鍵由數據庫自動生成(主要是支持自動增加的數據庫,如mysql)。
AUTO: 主鍵由程序控制,也是GenerationType的默認值。
dao層
@Repository
public interface AccountRepository extends JpaRepository<Account,String> {
}
複製代碼
controller層
@RestController
@RequestMapping(value = "/role")
public class AccountController {
@Autowired
private AccountRepository repository;
@PostMapping()
public Account save(@RequestBody Account account) {
return repository.save(account);
}
@DeleteMapping("/{id}")
public void delete(@PathVariable("id") String accountId) {
repository.deleteById(accountId);
}
@PutMapping("/{id}")
public Account update(@PathVariable("id") String accountId, @RequestBody Account account) {
account.setId(accountId);
return repository.saveAndFlush(account);
}
@GetMapping("/{id}")
public Account getAccountInfo(@PathVariable("id") String accountId) {
Optional<Account> optional = repository.findById(accountId);
return optional.orElseGet(Account::new);
}
}
複製代碼
最後在數據庫中造幾條假數據進行crud就能夠了。
Repository 接口概述:
public interface Repository<T, ID extends Serializable> { }
複製代碼
Repository 的子接口:
基礎的 Repository提供了最基本的數據訪問功能,其幾個子接口則擴展了一些功能。它們的繼承關係以下:
按照 Spring Data的規範,查詢方法以find | read | get
開頭,涉及條件查詢時,條件的屬性用條件關鍵字鏈接,要注意的是:條件屬性以首字母大寫。 好比說如今要按照account的名稱進行查詢:
在AccountRepository接口中新增方法
@Repository
public interface AccountRepository extends JpaRepository<Account,String> {
Account findAccountByUsername(String username);
}
複製代碼
controller中新增方法:
@GetMapping("/name/{username}")
public Account getAccountByName(@PathVariable("username") String userName){
Account account = repository.findAccountByUsername(userName);
return account;
}
複製代碼
這樣就能夠根據名稱進行查詢了,固然你也可使用這種方法進行復雜查詢,spring data jpa中支持的關鍵字以下:
有些時候spring data jpa提供的查詢條件知足不了業務需求的時候,可使用自定義的sql來進行查詢。
想要使用自定義sql須要使用@Query
註解,@Query註解使用起來很簡單,默認的屬性是value,就是當前寫的SQL語句,有時會用到nativeQuery屬性,這個屬性是用來標記當前的SQL是本地SQL,仍是符合JPA語法規範的SQL。這裏須要解釋一下本地SQL和JPA語法規範的SQL區別。
JPA很好的一個特性就是用JPA語法規範寫的SQL,會根據當前系統使用的數據庫類型改變生成的SQL語法,兼容數據庫類型的切換,如以前使用的是MySQL,如今換成Oracle,因爲不一樣類型的數據庫,SQL語法會有區別,若是使用的是mybatis,就須要手動去改SQL兼容Oracle,而JPA就不用啦,無縫對接。
很大的時候使用JPA感受都是爲了兼容後期可能會有數據庫切換的問題,因此在使用JPA的時候,不要去使用本地SQL,這就違背了使用JPA的初衷,讓nativeQuery屬性保持默認值就能夠啦!
AccountRepository中新增方法
@Query("select a from Account a where a.username = :username")
Account findAccountByName(@Param("username")String name);
@Query("select a from Account a where a.email = ?1")
Account findAccountByEmail(String email);
@Query(value = "select * from account where username = ?1",nativeQuery = true)
Account getAccount(String username);
複製代碼
@GetMapping("/sql/{username}")
public Account findAccountByName(@PathVariable("username") String userName){
Account account = repository.findAccountByName(userName);
return account;
}
@GetMapping("/email/{email}")
public Account findAccountByEmail(@PathVariable("email") String email){
Account account = repository.findAccountByEmail(email);
return account;
}
@GetMapping("/username/{username}")
public Account getAccount(@PathVariable("username") String username){
Account account = repository.getAccount(username);
return account;
}
複製代碼
最後經過請求就能夠得到數據而且在控制檯能夠看到打印出的響應的sql。
當自定義sql涉及到刪除,修改,插入的操做的時候須要加上@Modifying
註解。註明當前方法是修改操做。