Spring Data
一罗售、 學(xué)習(xí)安排
Spring-data、spring-boot、spring-cloud
Spring-data是一個spring提供的數(shù)據(jù)訪問層框架崭闲。封裝若干中數(shù)據(jù)服務(wù)訪問能力。如:spring-data-jpa威蕉、spring-data-jdbc刁俭、spring-data-redis等。
Spring-data-jpa: 是通過JPA標(biāo)準(zhǔn)規(guī)范韧涨,底層使用Hibernate框架做為實現(xiàn)牍戚,開發(fā)的關(guān)系型數(shù)據(jù)庫訪問模塊。
Spring-data-jdbc: 就是底層使用Spring-jdbc實現(xiàn)的關(guān)系型數(shù)據(jù)庫訪問模塊虑粥∪缧ⅲ可以使用Mybatis技術(shù)作為底層實現(xiàn)的替代產(chǎn)品。
Spring-data-redis:底層使用jedis實現(xiàn)的訪問redis數(shù)據(jù)服務(wù)的模塊娩贷。
上述三個描述的模塊是Spring-data中詳細(xì)講解的內(nèi)容第晰。其他的模塊非常多,不可能全部講解彬祖。主要作為介紹和配置簡單描述茁瘦。
二、 Spring Data 簡介
官網(wǎng): projects.spring.io/spring-data
Spring Data’s mission is to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store.
It makes it easy to use data access technologies, relational and non-relational databases, map-reduce frameworks, and cloud-based data services. This is an umbrella project which contains many subprojects that are specific to a given database. The projects are developed by working together with many of the companies and developers that are behind these exciting technologies.
Spring Data是一個保持底層數(shù)據(jù)存儲特性的储笑,基于Spring編程模型的甜熔,數(shù)據(jù)訪問技術(shù)。
Spring Data可以簡單快速的訪問關(guān)系型數(shù)據(jù)庫南蓬、非關(guān)系型數(shù)據(jù)庫纺非、map-reduce框架和基于云的數(shù)據(jù)服務(wù)。且Spring Data的開發(fā)有這些數(shù)據(jù)服務(wù)廠商和開發(fā)人員參與赘方。
總而言之烧颖,這是一個數(shù)據(jù)訪問層框架,可以高效的訪問現(xiàn)今絕大多數(shù)數(shù)據(jù)存儲服務(wù)窄陡,可以統(tǒng)一數(shù)據(jù)訪問層技術(shù)炕淮,讓開發(fā)和維護(hù)更加方便。
三跳夭、 Spring Data JPA
Java persistence api在spring-data工程中的具體應(yīng)用涂圆。
Spring-data-jpa底層是使用Hibernate實現(xiàn)的们镜。
Spring-data-jpa1.8.x+底層依賴的是Hibernate5.x版本的框架。
課程中使用的是spring-data-jpa1.11.x版本润歉。
底層使用Hibernate實現(xiàn)是因為Hibernate本身就是JPA標(biāo)準(zhǔn)規(guī)范的實現(xiàn)框架模狭。Hibernate又是經(jīng)歷了長時間商業(yè)項目驗證的穩(wěn)定的數(shù)據(jù)訪問層框架。所以spring-data-jpa選擇的是Hibernate作為底層實現(xiàn)踩衩。
1 Spring-DATA-JPA框架提供的接口的繼承樹
Spring-Data-JPA提供了若干的Repository接口嚼鹉,提供很多的關(guān)系型數(shù)據(jù)庫訪問能力。只要對Repository接口有足夠的掌握驱富,不需要寫SQL就可以使用數(shù)據(jù)庫的訪問操作锚赤。
1.1 類圖
1.2 Repository
標(biāo)記接口『峙福可以繼承此接口线脚,根據(jù)指定的規(guī)則,實現(xiàn)數(shù)據(jù)查詢叫榕。
1.2.1 方法名稱規(guī)則查詢
這種查詢也是有局限性的浑侥。只能做單表查詢,且查詢結(jié)果一定是實體類型對象或?qū)嶓w類型對象的集合翠霍。畢竟是一個InvocationHandler實現(xiàn)的模板代碼锭吨,難以完成絕對的定制化開發(fā)。只能實現(xiàn)最基礎(chǔ)的通用的功能寒匙×闳纾互聯(lián)網(wǎng)商業(yè)項目中,有半數(shù)以上的查詢是單表查詢锄弱。
命名規(guī)則:findBy(關(guān)鍵字)+屬性名稱(屬性名稱的首字母大寫)+查詢條件(首字母大寫)
關(guān)鍵字 | 方法命名 | sql where字句 |
---|---|---|
And | findByNameAndPwd | where name= ? and pwd =? |
Or | findByNameOrSex | where name= ? or sex=? |
Is,Equal | findById,findByIdEquals | where id= ? |
Between | findByIdBetween | where id between ? and ? |
LessThan | findByIdLessThan | where id < ? |
LessThanEqual | findByIdLessThanEquals | where id <= ? |
GreaterThan | findByIdGreaterThan | where id > ? |
GreaterThanEqual | findByIdGreaterThanEquals | where id > = ? |
After | findByIdAfter | where id > ? |
Before | findByIdBefore | where id < ? |
IsNull | findByNameIsNull | where name is null |
isNotNull,NotNull | findByNameNotNull | where name is not null |
Like | findByNameLike | where name like ? |
NotLike | findByNameNotLike | where name not like ? |
StartingWith | findByNameStartingWith | where name like '?%' |
EndingWith | findByNameEndingWith | where name like '%?' |
Containing | findByNameContaining | where name like '%?%' |
OrderBy | findByIdOrderByXDesc | where id=? order by x desc |
Not | findByNameNot | where name <> ? |
In | findByIdIn(Collection<?> c) | where id in (?) |
NotIn | findByIdNotIn(Collection<?> c) | where id not in (?) |
TRUE | findByAaaTue | where aaa = true |
FALSE | findByAaaFalse | where aaa = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |
1.2.2 @Query注解查詢
使用@Query注解描述方法考蕾,可以繞過方法命名規(guī)則,通過編寫JPQL或SQL來實現(xiàn)數(shù)據(jù)訪問会宪。
JPQL:java persistence 通過Hibernate的HQL演變過來的肖卧。他和HQL語法及其相似。JPQL語法查詢掸鹅,可以實現(xiàn)投影查詢塞帐,可以實現(xiàn)表連接查詢,畢竟是通過一種查詢語法規(guī)則實現(xiàn)的查詢邏輯巍沙。From Users葵姥、 select username from Users、from Users u,Roles r where u.xxx = r.xxx句携。JPQL語法查詢的時候榔幸,在JPQL(1.11.14)中,傳遞參數(shù)的時候,使用變量命名的方式削咆,通過’:變量名’來定義語法中的變量牍疏,方法的參數(shù)表中,通過@Param注解拨齐,描述方法參數(shù)表中的參數(shù)和JPQL中變量的對應(yīng)關(guān)系鳞陨,注解的屬性value代表JPQL中變量的名稱。
nativeQuery: 通過SQL語法實現(xiàn)數(shù)據(jù)查詢奏黑。效率更高的執(zhí)行邏輯炊邦。因為spring-data-jpa不需要實現(xiàn)JPQL->SQL的語法轉(zhuǎn)換编矾。少了JPQL字符串的解析熟史,SQL字符串的拼接等過程,效率相對更高窄俏。
語法如下:JPQL或SQL中的變量占位符順序?qū)?yīng)方法參數(shù)表中的參數(shù)順序蹂匹。
public interface IA{
@Query(value="JPQL")
List xxx();
@Query(value="SQL", nativeQuery=true)
List yyy();
}
1.2.3 @Query注解實現(xiàn)數(shù)據(jù)寫操作
@Query注解是用于描述數(shù)據(jù)訪問語法的,所以可以執(zhí)行CRUD任意操作凹蜈。但是JPQL只能執(zhí)行查詢和更新操作限寞,SQL可以執(zhí)行CRUD任意操作。語法如下:JPQL或SQL中的變量占位符順序?qū)?yīng)方法參數(shù)表中的參數(shù)順序仰坦。
public interface IA{
@Query(value="JPQL")
@Modifying
List xxx();
@Query(value="SQL", nativeQuery=true)
@Modifying
List yyy();
}
1.3 CrudRepository
定義了CRUD操作的接口履植,是Repository的子接口。接口中沒有定義獨立的更新方法悄晃,調(diào)用新增數(shù)據(jù)方法(save)的時候玫霎,底層會根據(jù)方法參數(shù)決定是新增數(shù)據(jù)還是更新數(shù)據(jù)。因為底層是Hibernate妈橄,Hibernate中有方法saveOrUpdate庶近,而spring-data-jpa中提供的save方法底層使用的就是Hibernate中的saveOrUpdate方法。判斷依據(jù)眷蚓,就是數(shù)據(jù)是否存在鼻种,就是數(shù)據(jù)對象的id是否存在。
1.4 PagingAndSortingRepository
定義了分頁和排序查詢的接口沙热,是CrudRepository的子接口叉钥。
1.5 JpaRepository
PagingAndSortingRepository的子接口,提供了對緩存的處理方法篙贸。
1.6 JpaSpecificationExecutor
提供了條件查詢和分頁處理的接口投队,是一個相對獨立的接口。這個接口的使用必須配合Repository接口樹中的任意接口歉秫。
2 自定義Repository
Spring-data-jpa做開發(fā)的時候蛾洛,一般不會去定義DAO接口的實現(xiàn)類。因為spring-data-jpa會提供一個動態(tài)代理對象,動態(tài)代理對象的類型是SimpleJpaRepository轧膘。
2.1 自定義Repository接口
定義一個Repository接口钞螟,不需要繼承任何接口,定義需要的自定義方法谎碍。
2.2 定義Dao接口
定義一個Dao接口鳞滨,這個接口是服務(wù)代碼調(diào)用的。Dao接口繼承spring-data-jpa提供的Repository接口和自定義的Repository接口蟆淀。
2.3 定義Dao接口實現(xiàn)
提供一個接口實現(xiàn)類拯啦,這個實現(xiàn)類只需要實現(xiàn)自定義Repository接口,但是其類名必須和Dao接口相關(guān)熔任,命名規(guī)則為"Dao接口名Impl"褒链,如:Dao接口為UserDao,實現(xiàn)類命名為UserDaoImpl疑苔,實現(xiàn)類實現(xiàn)接口Repository甫匹。
符合上述要求的代碼spring-data-jpa會自動為Dao創(chuàng)建一個動態(tài)代理對象,這個動態(tài)代理對象會提供spring-data-jpa定義的Repository相關(guān)代碼實現(xiàn)惦费,并使用自定義的接口實現(xiàn)類提供自定義Repository接口的方法實現(xiàn)兵迅。
類圖如下:
3 Spring-data-jpa正向工程建表
在默認(rèn)情況下(spring-data-jpa 1.11.x),spring-data-jpa使用正向工程創(chuàng)建的數(shù)據(jù)庫表格薪贫,是有默認(rèn)配置的恍箭,其建表語句如下:
create table tb_users (
userid integer not null auto_increment,
userage integer,
username varchar(255),
primary key (userid)
) engine=MyISAM
Spring-data-jpa默認(rèn)情況下,創(chuàng)建的MySQL數(shù)據(jù)庫表格是MyISAM引擎的表格瞧省。這種表格扯夭,適合查詢,不支持事務(wù)臀突,不支持外鍵約束勉抓。
但是,因為其不支持事務(wù)候学,所有有臟數(shù)據(jù)出現(xiàn)的可能藕筋。
可以在配置LocalContainerEntityManagerFactoryBean的時候,增加配置信息梳码,約束建表的引擎隐圾。
<!-- Spring整合JPA 配置EntityManagerFactory-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!-- hibernate相關(guān)的屬性的注入 -->
<!-- 配置數(shù)據(jù)庫類型 -->
<property name="database" value="MYSQL"/>
<!-- 正向工程 自動創(chuàng)建表 -->
<property name="generateDdl" value="true"/>
<!-- 顯示執(zhí)行的SQL -->
<property name="showSql" value="true"/>
<!-- 提供數(shù)據(jù)庫特性配置。和數(shù)據(jù)庫的獨特功能緊密相關(guān)掰茶。這個配置是使用Hibernate提供的Dialect來配置的暇藏。 -->
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
</bean>
</property>
<!-- 掃描實體的包 -->
<property name="packagesToScan">
<list>
<value>com.bjsxt.pojo</value>
</list>
</property>
</bean>
修改配置后,建表語句如下:
create table tb_users (
userid integer not null auto_increment,
userage integer,
username varchar(255),
primary key (userid)
) engine=InnoDB
是否需要配置數(shù)據(jù)庫特性濒蒋,由具體業(yè)務(wù)決定盐碱。一般來說把兔,商業(yè)項目中,不可能使用正向工程建表瓮顽。也就是說县好,配置應(yīng)該是<property name="generateDdl" value="false"/>
4 關(guān)聯(lián)操作
關(guān)聯(lián)操作在spring-data-jpa中主要通過JPA注解來實現(xiàn)。如:@OneToOne暖混、@OneToMany缕贡、@ManyToOne、@ManyToMany拣播、@JoinColumn晾咪、@JoinTable等。
詳見代碼贮配。
四谍倦、 Spring Data Redis
spring-data框架中的每個子模塊其版本未必一致,畢竟對應(yīng)不同數(shù)據(jù)服務(wù)的訪問層框架牧嫉,更新時間和周期是不同的剂跟。在本案例中,使用的spring-data-redis版本為1.8.14酣藻。
spring-data-redis框架的執(zhí)行需要jackson組件的輔助,建議導(dǎo)入jackson版本為2.7+(對應(yīng)當(dāng)前環(huán)境中的spring-data-redis版本)鳍置。