1. 程式人生 > >SpringBoot(三)springboot整合SpringDataJPA

SpringBoot(三)springboot整合SpringDataJPA

        在我們的專案開發中,資料庫的訪問及儲存都是最為核心的部分,SpringBoot為我們提供了多種資料庫來做資料的儲存及讀取。目前企業開發中應用最為廣泛的資料庫有,關係型資料庫MySQL,oracle,sqlserver,非關係型資料庫redis,mongodb等。         本章將通過使用SpringBoot訪問MySQL結合SpringDataJPA完成CRUD(Create,Read,Update,Delete)簡單操作。

  一 、什麼是SpringDataJPA

    Spring Data是一個用於簡化資料庫訪問,並支援雲服務的開源框架,其主要目標是使得對資料的訪問變得方便快捷。Spring Data包含多個子專案,spring-data-jpa就是其子專案之一。

     JPA(Java Persistence API)是一種Java持久化解決方案,負責把資料儲存到資料庫,實際上它就是一種標準、規範,而不是具體的實現。JPA屬於重量級的,因為它需要執行在JAVA EE容器中,而Spring Data JPA提供了輕量級的實現,在任何servlet容器中都可以執行。      Spring Data JPA相對於JAVA EE中的JPA,配置更簡單,以輕量級的方式實現了部分在 EJB 容器環境下才具有的功能,將 EntityManager 的建立與銷燬、事務管理等程式碼抽取出來,並由其統一管理,並且極大的簡化了資料庫訪問層的程式碼。

   二、springboot整合SpringDataJPA

    1. 建立資料庫表

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    2.  新增依賴

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.45</version>
    </dependency>
    <!--入JPA的依賴關係-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    3.  配置資料來源

spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=
#jpa連線的資料庫型別
spring.jpa.database=mysql

    4. 編寫實體類

import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;

/*
 * @author uv
 * @date 2018/9/14 14:29
 *
 */
@Entity // 對實體註釋。任何Hibernate對映物件都要有這個註釋
@Table(name = "user") //@Table註釋指定了Entity所要對映帶資料庫表
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)  // 主鍵生成策略
    private int id;
    private String name;
    private String password;

//    @Transient //在進行單表的增刪改查的時候即忽略這個欄位
//    private int age;

    //get,set 方法
}

     5. 編寫dao介面

package com.uv.boot.dao;
/*
 * @author uv
 * @date 2018/9/14 16:28
 *
 */

import com.uv.boot.entity.User;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

// JpaRepository<User,Integer> 查詢的實體類和主鍵的資料型別
public interface UserDao extends JpaRepository<User,Integer>,JpaSpecificationExecutor<User>,Serializable {
    
}

       我們並不需要做其他的任何操作了,因為SpringBoot以及SpringDataJPA會為我們全部搞定,SpringDataJPA內部使用了類代理的方式讓繼承了它介面的子介面都以spring管理的Bean的形式存在。

       JpaRepository的原始碼,預設的CRUD有如下方法:

@NoRepositoryBean //此註解表示不進行實體類與表的對映,多用於實體類的父類
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    
    List<T> findAll();  //查詢所有資料

    List<T> findAll(Sort var1);  //按條件查詢

    List<T> findAll(Iterable<ID> var1); 

    <S extends T> List<S> save(Iterable<S> var1);

    void flush();

    <S extends T> S saveAndFlush(S var1);

    void deleteInBatch(Iterable<T> var1);

    void deleteAllInBatch();

    T getOne(ID var1);

    <S extends T> List<S> findAll(Example<S> var1);

    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

SpringDataJpa可以根據方法自動對映成Sql語句,真正的實現不用寫一句Sql語句,對映關係如下:

      6. 編寫UserService和UserController

package com.uv.boot.service;

import com.uv.boot.dao.UserDao;
import com.uv.boot.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/*
 * @author uv
 * @date 2018/9/14 14:56
 *
 */
@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void insertUser(User user) {
        userDao.save(user);
    }

    public User getUser(int id) {
        return userDao.getOne(id);
    }
}
package com.uv.boot.controller;

import com.uv.boot.entity.User;
import com.uv.boot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/*
 * @author uv
 * @date 2018/9/14 14:59
 *
 */
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("insertuser")
    public void insertUser(User user) {
        userService.insertUser(user);
    }

    @GetMapping("getuser")
    public User getUser(int id) {
        return userService.getUser(id);
    }

}

      7. 啟動類新增掃描

@SpringBootApplication
@EnableJpaRepositories(basePackages = {"com.uv.boot.dao"})	//掃描repository
@EntityScan(basePackages = {"com.uv.boot.entity"})	//掃描entity實體
public class BootApplication {

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

     8. 測試

    9. 在測試中出現的異常

"exception": "org.springframework.http.converter.HttpMessageNotWritableException",
    "message": "Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.uv.boot.entity.User_$$_jvst166_0[\"handler\"])",

      解決:

      hibernate延時載入     因為jsonplugin用的是Java的內審機制.hibernate會給被管理的pojo加入一個hibernateLazyInitializer屬性,jsonplugin會把  hibernateLazyInitializer也拿出來操作,並讀取裡面一個不能被反射操作的屬性就產生了這個異常. 然後在型別上面將hibernateLazyInitializer進行忽略。

因此在User實體類上新增:@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })