JPA介紹
JPA(Java Persistence API)是Sun官方提出的Java持久化規(guī)范古掏。它為Java開發(fā)人員提供了一種對象/關聯(lián)映射工具來管理Java應用中的關系數(shù)據(jù)盘榨。他的出現(xiàn)主要是為了簡化現(xiàn)有的持久化開發(fā)工作和整合ORM技術壶运,結(jié)束現(xiàn)在Hibernate剑勾,TopLink炉爆,JDO等ORM框架各自為營的局面榜配。值得注意的是祠汇,JPA是在充分吸收了現(xiàn)有Hibernate,TopLink失暂,JDO等ORM框架的基礎上發(fā)展而來的彼宠,具有易于使用,伸縮性強等優(yōu)點弟塞。
注意:JPA是一套規(guī)范凭峡,不是一套產(chǎn)品,那么像Hibernate,TopLink,JDO他們是一套產(chǎn)品决记,如果說這些產(chǎn)品實現(xiàn)了這個JPA規(guī)范摧冀,那么我們就可以叫他們?yōu)镴PA的實現(xiàn)產(chǎn)品。
Spring Data JPA
Spring Data JPA 是 Spring 基于 ORM 框架系宫、JPA 規(guī)范的基礎上封裝的一套JPA應用框架索昂,可使開發(fā)者用極簡的代碼即可實現(xiàn)對數(shù)據(jù)的訪問和操作。它提供了包括增刪改查等在內(nèi)的常用功能扩借,且易于擴展椒惨!學習并使用 Spring Data JPA 可以極大提高開發(fā)效率!Spring Data JPA讓我們解脫了DAO層的操作往枷,基本上所有CRUD都可以依賴于它來實現(xiàn)框产。
構建項目
打開pom.xml添加相關依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- 分頁插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.0.0</version>
</dependency>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置數(shù)據(jù)源以及JPA
spring.datasource.url=jdbc:mysql://127.0.0.1/spring?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql= true
#pagehelper
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
pagehelper.params=count=countSql
spring.jpa.properties.hibernate.hbm2ddl.auto 是hibernate的配置屬性
- create:每次加載hibernate時都會刪除上一次的生成的表,然后根據(jù)你的model類再重新來生成新表错洁,哪怕兩次沒有任何改變也要這樣執(zhí)行秉宿,這就是導致數(shù)據(jù)庫表數(shù)據(jù)丟失的一個重要原因。
- create-drop:每次加載hibernate時根據(jù)model類生成表屯碴,但是sessionFactory一關閉,表就自動刪除描睦。
- validate:每次加載hibernate時,驗證創(chuàng)建數(shù)據(jù)庫表結(jié)構导而,只會和數(shù)據(jù)庫中的表進行比較忱叭,不會創(chuàng)建新表,但是會插入新值今艺。
- update:最常用的屬性韵丑,第一次加載hibernate時根據(jù)model類會自動建立起表的結(jié)構(前提是先建立好數(shù)據(jù)庫),以后加載hibernate時根據(jù)model類自動更新表結(jié)構虚缎,即使表結(jié)構改變了但表中的行仍然存在不會刪除以前的行撵彻。要注意的是當部署到服務器后,表結(jié)構是不會被馬上建立起來的,是要等應用第一次運行起來后才會陌僵。
創(chuàng)建實體
@Entity
public class User {
@Id
@GeneratedValue
private long id;
@Column(nullable = false,unique = true)
private String userName;
@Column(nullable = false)
private String passWord;
@Column(nullable = false)
private int age;
......省略set/get方法
}
繼承JpaRepository接口(SpringDataJPA提供的簡單數(shù)據(jù)操作接口轴合、JpaSpecificationExecutor(復雜查詢接口)、Serializable(序列化接口)碗短。通過查看JpaRepository接口的API文檔受葛,可以看到該接口本身已經(jīng)實現(xiàn)了創(chuàng)建(save)、更新(save)偎谁、刪除(delete)总滩、查詢(findAll)等基本操作的函數(shù),因此對于這些基礎操作的數(shù)據(jù)訪問就不需要開發(fā)者再自己定義搭盾。
public interface UserRepository extends JpaRepository<User,Long>,
JpaSpecificationExecutor<UserEntity>,
Serializable{
}
用@RestController注解來編寫一個控制器
SpringDataJPA內(nèi)部使用了類代理的方式讓繼承了它接口的子接口都以spring管理的Bean的形式存在咳秉,我們可以直接使用@Autowired注解在spring管理bean使用婉支。
@RestController
public class UserController {
@Autowired
private UserRepository userRepository;
/*@RequestMapping(value = "/list")
public List<User> list(){
return userRepository.findAll();
}*/
/**
* 查詢?nèi)苛斜?并做分頁
* @param pageNum 開始頁數(shù)
* @param pageSize 每頁顯示的數(shù)據(jù)條數(shù)
*/
@RequestMapping(value = "/list/{pageNum}/{pageSize}")
public List<User> list(@PathVariable("pageNum") int pageNum, @PathVariable("pageSize") int pageSize){
//將參數(shù)傳給這個方法就可以實現(xiàn)物理分頁了鸯隅,非常簡單。
Sort sort = new Sort(Sort.Direction.ASC, "id");
Pageable pageable = new PageRequest(pageNum, pageSize, sort);
Page<User> users = userRepository.findAll(pageable);
List<User> list = users.getContent();
return list;
}
/**
* 如果需要執(zhí)行持久化的實體存在主鍵值則更新數(shù)據(jù)向挖,如果不存在則添加數(shù)據(jù)
*/
@RequestMapping(value = "/save")
public User save(User user){
return userRepository.save(user);
}
@RequestMapping(value = "/delete")
public List<User> delete(long id){
userRepository.deleteById(id);
return userRepository.findAll();
}
@RequestMapping(value = "/find")
public User find(long id){
return userRepository.findById(id).get();
}
}
自定義簡單查詢
自定義的簡單查詢就是根據(jù)方法名來自動生成SQL
public interface UserRepository extends JpaRepository<User, Long> {
User findByUserName(String userName);
User findByUserNameOrEmail(String username, String email);
Long deleteById(Long id);
Long countByUserName(String userName);
List<User> findByEmailLike(String email);
User findByUserNameIgnoreCase(String userName);
List<User> findByUserNameOrderByEmailDesc(String email);
......
}
分頁查詢
spring data jpa已經(jīng)幫我們實現(xiàn)了分頁的功能蝌以,在查詢的方法中,需要傳入?yún)?shù)Pageable ,當查詢中有多個參數(shù)的時候Pageable建議做為最后一個參數(shù)傳入
Page<User> findALL(Pageable pageable);
Page<User> findByUserName(String userName,Pageable pageable);
Pageable 是spring封裝的分頁實現(xiàn)類何之,使用的時候需要傳入頁數(shù)跟畅、每頁條數(shù)和排序規(guī)則
@Test
public void testPageQuery() throws Exception {
int page=1,size=10;
Sort sort = new Sort(Direction.DESC, "id");
Pageable pageable = new PageRequest(page, size, sort);
userRepository.findALL(pageable);
userRepository.findByUserName("testName", pageable);
}
限制查詢
有時候我們只需要查詢前N個元素,或者支取前一個實體溶推。
ser findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
自定義SQL查詢
在SQL的查詢方法上面使用@Query注解徊件,如涉及到刪除和修改在需要加上@Modifying.也可以根據(jù)需要添加 @Transactional 對事物的支持,查詢超時的設置等蒜危。
@Modifying
@Query("update User u set u.userName = ?1 where u.id = ?2")
int modifyByIdAndUserId(String userName, Long id);
@Transactional
@Modifying
@Query("delete from User where id = ?1")
void deleteByUserId(Long id);
@Transactional(timeout = 10)
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
多表查詢
多表查詢在spring data jpa中有兩種實現(xiàn)方式虱痕,第一種是利用hibernate的級聯(lián)查詢來實現(xiàn),第二種是創(chuàng)建一個結(jié)果集的接口來接收連表查詢后的結(jié)果辐赞,這里主要第二種方式部翘。
首先需要定義一個結(jié)果集的接口類。
public interface HotelSummary {
City getCity();
String getName();
Double getAverageRating();
default Integer getAverageRatingRounded() {
return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
}
}
查詢的方法返回類型設置為新創(chuàng)建的接口
@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
- "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);
@Query("select h.name as name, avg(r.rating) as averageRating "
- "from Hotel h left outer join h.reviews r group by h")
Page<HotelSummary> findByCity(Pageable pageable);
使用
Page<HotelSummary> hotels = this.hotelRepository.findByCity(new PageRequest(0, 10, Direction.ASC, "name"));
for(HotelSummary summay:hotels){
System.out.println("Name" +summay.getName());
}
在運行中Spring會給接口(HotelSummary)自動生產(chǎn)一個代理類來接收返回的結(jié)果响委,代碼匯總使用getXXX的形式來獲取
多數(shù)據(jù)源的支持
同源數(shù)據(jù)庫的多源支持
日常項目中因為使用的分布式開發(fā)模式新思,不同的服務有不同的數(shù)據(jù)源,常常需要在一個項目中使用多個數(shù)據(jù)源赘风,因此需要配置sping data jpa對多數(shù)據(jù)源的使用夹囚,一般分一下為三步:
- 1 配置多數(shù)據(jù)源
- 2 不同源的實體類放入不同包路徑
- 3 聲明不同的包路徑下使用不同的數(shù)據(jù)源、事務支持
異構數(shù)據(jù)庫多源支持
比如我們的項目中邀窃,即需要對mysql的支持荸哟,也需要對mongodb的查詢等。
實體類聲明@Entity 關系型數(shù)據(jù)庫支持類型、聲明@Document 為mongodb支持類型敲茄,不同的數(shù)據(jù)源使用不同的實體就可以了位谋。
interface PersonRepository extends Repository<Person, Long> {
…
}
@Entity
public class Person {
…
}
interface UserRepository extends Repository<User, Long> {
…
}
@Document
public class User {
…
}
但是,如果User用戶既使用mysql也使用mongodb呢堰燎,也可以做混合使用
interface JpaPersonRepository extends Repository<Person, Long> {
…
}
interface MongoDBPersonRepository extends Repository<Person, Long> {
…
}
@Entity
@Document
public class Person {
…
}
也可以通過對不同的包路徑進行聲明掏父,比如A包路徑下使用mysql,B包路徑下使用mongoDB
@EnableJpaRepositories(basePackages = "com.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.repositories.mongo")
interface Configuration { }