1. 程式人生 > >使用Gradle構建SpringBoot工程系列:第八篇:使用spring-data-jpa 實現資料持久化

使用Gradle構建SpringBoot工程系列:第八篇:使用spring-data-jpa 實現資料持久化

本篇文章是SpringBoot 系列文章的第八篇文章,由於本人工作原因,中斷了一段時間,接下來的一段時間裡,將陸續更新本系列的其他文章,迴歸Spring Boot技術體系,記錄本人學習和使用Gradle構建spring Boot工程的過程、技術要點以及在過程中遇到的各種問題,歡迎廣大程式猿共同關注學習,也歡迎大家提出自己的寶貴意見,知識在交流中碰撞,技術在交流中提升!

 Spring Data JPA

是Spring Data系列的一部分,可以輕鬆實現基於JPA的資料持久化操作,旨在通過提供通用介面減少持久層的編碼量,提高程式碼質量,降低程式碼和SQL的維護成本,避免SQL注入等安全風險。作為開發人員只需編寫Repostitory介面,Spring將自動提供實現資料庫讀寫

Repository的概念

在Spring中有Repository的概念,repository原意指的是倉庫,即資料倉庫的意思。Repository居於業務層和資料層之間,將兩者隔離開來,在它的內部封裝了資料查詢和儲存的邏輯。這樣設計的好處有兩個:

  1. 降低層級之間的耦合:更換、升級ORM引擎(Hibernate)並不會影響業務邏輯
  2. 提高測試效率:如果在測試時能用Mock資料物件代替實際的資料庫操作,執行速度會快很多

Repository和DAO的區別

DAO是傳統MVC中Model的關鍵角色,全稱是Data Access Object。DAO直接負責資料庫的存取工作,乍一看兩者非常類似,但從架構設計上講兩者有著本質的區別:

Repository蘊含著真正的OO概念,即一個數據倉庫角色,負責所有物件的持久化管理。DAO則沒有擺脫資料的影子,仍然停留在資料操作的層面上。Repository是相對物件而言,DAO則是相對資料庫而言,雖然可能是同一個東西 ,但側重點完全不同。

接下來本篇文章將針對使用CrudRepository實現Repository資料庫讀寫:

在Gradle 的build.gradle配置檔案中追加一下jpa依賴:'org.springframework.boot:spring-boot-starter-data-jpa' 

dependencies {
    compile(
            'org.springframework.boot:spring-boot-starter-actuator',
            'org.springframework.boot:spring-boot-starter-web',
            'org.springframework.boot:spring-boot-starter-data-jpa',
            'org.springframework.boot:spring-boot-devtools',
            'mysql:mysql-connector-java'
    )
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

對於使用maven的朋友可以使用一下配置:

<!-- spring boot 父節點依賴,
       引入這個之後相關的引入就不需要新增version配置,
        spring boot會自動選擇最合適的版本進行新增。
    -->
    <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>1.3.3.RELEASE</version>
    </parent>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
     
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
        <!-- spring boot jpa支援:... -->
      <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-jpa</artifactId>
       </dependency>

application.yml或propertites引入資料來源配置:

application.yml:

#本地環境
spring:
  profiles: local
 
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/bootdb?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
    username: root
    password: root
 
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

application.properties 

########################################################
###datasource  配置MySQL資料來源;
########################################################
spring.datasource.url = jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.max-active=20
spring.datasource.max-idle=8
spring.datasource.min-idle=8
spring.datasource.initial-size=10

########################################################
### Java Persistence Api 自動進行建表
########################################################
# 指定資料來源型別
spring.jpa.database = MYSQL
# 指定是否在控制檯輸出SQL語句
spring.jpa.show-sql = true
# 支援自動建表 Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# 命名策略(Naming strategy):用於指定實體與表對映的命名規範,可以使用自定義策略
# 這裡使用自帶的策略
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# 資料庫方言 stripped before adding them to the entity manager)
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

CrudRepository提供的基本的讀寫方法

  <S extends T> S save(S entity);
  <S extends T> Iterable<S> save(Iterable<S> entities);
  T findOne(ID id);
  boolean exists(ID id);
  Iterable<T> findAll();
  Iterable<T> findAll(Iterable<ID> ids);
  long count();
  void delete(ID id);
  void delete(T entity);
  void delete(Iterable<? extends T> entities);
  void deleteAll();

CrudRepository類如其名,可以勝任最基本的CRUD操作。其中save方法在可兩用,引數中不存在主鍵時執行insert操作,存在主鍵則執行update操作,相當於是一個upsert操作。

建立實體類:此類即代表資料庫表實體,也代表資料庫表結構,可以通過註解指定實體關聯關係

@Entity
public class UserInfo implements Serializable{
    private static final long serialVersionUID = 1L;
    @[email protected]
    private long uid;//使用者id;
   
    @Column(unique=true)
    private String username;//賬號.
   
    private String name;//名稱(暱稱或者真實姓名,不同系統不同定義)
   
    private String password; //密碼;
    private String salt;//加密密碼的鹽
   
    private byte state;//使用者狀態,0:建立未認證(比如沒有啟用,沒有輸入驗證碼等等)--等待驗證的使用者 , 1:正常狀態,2:使用者被鎖定.
 
   
    @ManyToMany(fetch=FetchType.EAGER)//立即從資料庫中進行載入資料;
    @JoinTable(name = "SysUserRole", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns ={@JoinColumn(name = "roleId") })
    private List<SysRole> roleList;// 一個使用者具有多個角色
   
    public List<SysRole> getRoleList() {
       return roleList;
    }
 
    public void setRoleList(List<SysRole> roleList) {
       this.roleList = roleList;
    }

建立介面實現類:

/**
* UserInfo持久化類:實現CrudRepository,介面,並制定介面泛型,即與指定的實體表進行繫結;
* @author 
* @version v.0.1
*/
public interface UserInfoRepository extends CrudRepository<UserInfo,Long>{
  
   /**通過username查詢使用者資訊;此處無需寫出具體sql,但方法名稱必須符合命名策略
    * 
    */
   public UserInfo findByUsername(String username);
  
}

建立Service層實現:此處service介面層可自行定義,此處僅代表示例

/**
 * service層可直接注入 我們實現Repostitory介面
 */
@Service
public class UserInfoServiceImpl implements UserInfoService{
   
    @Resource
    private UserInfoRepository userInfoRepository;
   
    @Override
    public UserInfo findByUsername(String username) {
       System.out.println("UserInfoServiceImpl.findByUsername()");
       return userInfoRepository.findByUsername(username);
    }
    /**
     * 這裡的save方法是CrudRepository預設提供的
     */
	@Override
	public void UserInfoSave(UserInfo userInfo) {
		System.out.println("UserInfoServiceImpl.UserInfoSave()");
		 userInfoRepository.save(userInfo);
	}
    
   
}

編寫Controller層實現: 

@Controller
@RequestMapping("/userInfo")
public class UserInfoController {
	@Autowired
    UserInfoService userInfoService;
    /**
     * 使用者查詢.使用自定義方法
     * @return
     */
    @RequestMapping(value="/user",method=RequestMethod.GET)
    public String userInfo(@RequestParam String username){
    	userInfoService.findByUsername(username);
       return "userInfo";
    }
   
    /**
     * 使用者新增 使用系統自帶方法;
     * @return
     */
    @RequestMapping(value="/user",method=RequestMethod.POST)
    public String userInfoAdd(@RequestBody UserInfo userInfo){
    	userInfoService.userInfoSave(userInfo);
       return "userInfoAdd";
    }
   
}

以上是本篇文章的相關實戰程式碼,通過以上實現,啟動SpringBoot應用,會自動建立UserInfo表,

可以通過POSTMAN等軟體進行介面測試:

新增使用者資訊:

查詢我們新增的使用者資訊:'127.0.0.1:8080/userinfo?username=zhangsan',得到以下結果:

擴充套件:Spring Boot 也提供了其他Repository介面,例如:JpaRepository

JpaRepository繼承自CrudRepostitory,並提供的基本方法:

  List<T> findAll();
  List<T> findAll(Sort sort);
  List<T> findAll(Iterable<ID> ids);
  <S extends T> List<S> save(Iterable<S> entities);
  void flush();
  <S extends T> S saveAndFlush(S entity);
  void deleteInBatch(Iterable<T> entities);
  void deleteAllInBatch();
  T getOne(ID id);
  @Override
  <S extends T> List<S> findAll(Example<S> example);
  @Override
  <S extends T> List<S> findAll(Example<S> example, Sort sort);

JpaRepository則進一步擴充套件了部分功能:

  1. 查詢列表(返回值為List)
  2. 批量刪除
  3. 強制同步
  4. Example查詢

在接下來的文章中將進行實踐,敬請期待