一、什么是JPA
JPA(Java Persistence API)定義了一系列對象持久化的標准,目前實現這一規范的產品有Hibernate、TopLink等。
二、Mysql數據庫示例
1、在application.yml文件中增加數據庫訪問的配置
ddl-auto:可選屬性有以下幾種。
create 每次創建一個新表,那么之前表中的數據都會丟掉
update 表不存在的時候才會建立新表,如果存在則不會新建,所以原有數據不會丟
create-drop 每次新建一個表,而且服務停掉,那么所建立的表會隨之刪除
none 見名知意,就是什么都不做,不會給幫你建表,只能使用現有的表
validate 會將實體類和表進行一個驗證,如果不一致會報錯
2、新建實體類
package com.zmfx.jpa; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Dog { /* 如果這些注解所在的包,javax.persistence不能導入。可能是缺少依賴 可以在pom中加入Javax Persistence API 的依賴 */ @Id @GeneratedValue private Integer id;//編號 private Integer age;//年齡 private String name;//名字 public Dog() { } public Dog(Integer id, Integer age, String name) { this.id = id; this.age = age; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3、編寫Repository接口類
這里需要繼承JpaRepository這個類,這樣我們就可以使用底層幫我們實現好的一些代碼
相當於我們之前了解到的持久層(數據訪問層),用於獲取數據庫中的數據。
4、編寫Serivce層
按照策略模式,我們應當一個接口,然后對應實現類。由於這里業務比較簡單,我們就不那么費事了。可能這層我在下面都不寫。
5、編寫Controller層
根據訪問信息,進行相應的業務處理,頁面展示。
三、RestFul API
1、查詢所有,findAll()方法的使用。GET請求
Repository接口類
package com.zmfx.jpa; import org.springframework.data.jpa.repository.JpaRepository; /** * 這個接口需要繼承一個接口JpaRepository * 這樣就可以使用底層為我們編寫好的一些通用方法 */ public interface DogRepository extends JpaRepository<Dog,Integer> { }
Controller層
package com.zmfx.jpa; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * 控制層 */ @RestController public class DogController { //因為業務太簡單,所有我們省略service層,直接調用數據訪問層的代碼 @Autowired private DogRepository dogRepository; /** * 查詢所有女生列表 * @return */ @GetMapping(value="/dogs") public List<Dog> dogList(){ return dogRepository.findAll();//findAll()方法是底層幫我沒實現好的 } }
這里推薦一個軟件PostMan,可以模擬前端的http訪問,可以不用編寫頁面
2、根據id查詢一條記錄,findById()的使用,GET請求
在controller中新加以下代碼
/** * 根據id查詢指定的Dog * @param id * @return */ @GetMapping(value = "/dog/{id}") public Optional<Dog> findDogById(@PathVariable("id") Integer id){ return dogRepository.findById(id);//注意這個方法的返回值 }
然后,使用PostMan進行訪問,展示如下:
3、添加一個Dog,save()方法的使用,POST請求
controller層中新加以下代碼
/** * 添加一個Dog * @param age * @param name * @return */ @PostMapping(value = "/addDog") public Dog addDog(@RequestParam("age") Integer age, @RequestParam("name") String name){ Dog dog=new Dog(); dog.setAge(age); dog.setName(name); return dogRepository.save(dog); }
然后用PostMan進行訪問,展示效果如下:
4、更新dog的信息,save()方法的使用,Put請求
在controller增加下面代碼
/** * 更新Dog信息 * @param id * @param age * @param name * @return */ @PutMapping(value = "updateDog/{id}") public Dog updateDog(@PathVariable("id") Integer id, @RequestParam("age") Integer age, @RequestParam("name") String name){ Dog dog=new Dog(); dog.setId(id); dog.setName(name); dog.setAge(age); System.out.println(dog); return dogRepository.save(dog);//注意這里使用save()方法,根據主鍵,所以主鍵不能更改 }
這里使用PostMan的PUT請求,注意使用x-www-form-urlencoded進行傳參
訪問后的效果應當如下:
5、刪除一條記錄,deleteById()方法,DELETE請求
controller中加入以下代碼:
/** * 刪除一條記錄 * @param id */ @DeleteMapping(value = "/del/{id}") public void delDogById(@PathVariable("id") Integer id){ dogRepository.deleteById(id); }
PostMan中使用DELETTE請求,因為沒有返回值,所以需要到數據庫中查看效果
6、根據年齡來查詢,自己在Repository中定義
DogRepository中變為
package com.zmfx.jpa; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; /** * 這個接口需要繼承一個接口JpaRepository * 這樣就可以使用底層為我們編寫好的一些通用方法 */ public interface DogRepository extends JpaRepository<Dog,Integer> { //通過年齡來查詢 List<Dog> findByAge(Integer age);//注意方法名的格式,findBy+屬性名。 }
Controller中新增代碼
/** * 根據年齡來查詢 */ @GetMapping(value = "/dogs/{age}") public List<Dog> dogList(@PathVariable("age")Integer age){ return dogRepository.findByAge(age); }
然后使用PostMan進行訪問,展示如下:
四、事務管理
1、加入事務之前
controller層加入代碼
//這里涉及到事務,所以我們加入service的依賴 @Autowired private DogService dogService; /** * 事務測試的方法 */ @GetMapping(value = "/dogs/tx") public void txTest(){ System.out.println("進入了controller"); dogService.addTwoDog(); }
service層代碼,這里用到了事務,所以要新建一個DogService類
package com.zmfx.jpa; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class DogService { @Autowired private DogRepository dogRepository; /** * 同時添加兩條記錄 */ public void addTwoDog(){ //模擬兩條數據 Dog dog1=new Dog(); dog1.setAge(2); dog1.setName("小黑1"); //模擬第二條數據 Dog dog2=new Dog(); dog2.setAge(2); dog2.setName("小黑2"); System.out.println("進入了service"); //將數據插入到數據庫 dogRepository.save(dog1); System.out.println(5/0);//模擬異常 dogRepository.save(dog2); } }
然后使用 http://127.0.0.1:8083/dev/dogs/tx 進行訪問,我們發現后台拋出異常,但是數據庫還是添加了第一條的記錄。
2、加入事務之后
我們就能夠讓小黑1 和 小黑2 同生共死了。
其它的都不變,然后再需要添加事務的方法上,添加一個@Transactional注解。也就是service的 public void addTwoDog()上加入注解
package com.zmfx.jpa; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class DogService { @Autowired private DogRepository dogRepository; /** * 同時添加兩條記錄 */ @Transactional //加入事務控制 public void addTwoDog(){ //模擬兩條數據 Dog dog1=new Dog(); dog1.setAge(2); dog1.setName("小黑1"); //模擬第二條數據 Dog dog2=new Dog(); dog2.setAge(2); dog2.setName("小黑2"); System.out.println("進入了service"); //將數據插入到數據庫 dogRepository.save(dog1); System.out.println(5/0);//模擬異常 dogRepository.save(dog2); } }
然后刪除數據庫中,小黑1這條記錄,重啟springboot服務,再次訪問 http://127.0.0.1:8083/dev/dogs/tx 。
還是那個異常,然后去看數據庫,發現兩條記錄都沒有添加進來。事務控制添加成功。