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" })