JPA : Java Persistence API, Java持久層API,是JDK 5.0註解或XML描述對象-關係表的映射關係,並將運行期的實體對象持久化到數據庫中。java
Spring Data JPA 是Spring基於ORM框架、JPA規範封裝的一套JPA應用框架,可以使開發者用極簡的代碼便可實現對數據的訪問和操做。它提供了包括增刪改查等在內的經常使用功能,且易於擴展!學習並使用SpringDataJPA能夠極大提升開發效率! 除了CRUD外,還包括如分頁、排序等一些經常使用的功能。下面的示例代碼便可完成數據保存的操做,而無需具體實現類.mysql
public interface UserDao extends Repository<AccountInfo, Long> {
public AccountInfo save(AccountInfo accountInfo);
}
spring
CrudRepository :是Repository的子接口,提供CRUD的功能sql
PagingAndSortingRepository:是CrudRepository的子接口,添加分頁和排序的功能數據庫
JpaRepository:是PagingAndSortingRepository的子接口,增長了一些實用的功能,好比:批量操做等。apache
JpaSpecificationExecutor:用來作負責查詢的接口app
Specification:是Spring Data JPA提供的一個查詢規範,要作複雜的查詢,只需圍繞這個規範來設置查詢條件便可框架
導入依賴dom
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 <groupId>com.cenobitor</groupId> 5 <artifactId>JPADemo</artifactId> 6 <version>0.0.1-SNAPSHOT</version> 7 <packaging>pom</packaging> 8 <description>統一管理依賴</description> 9 10 <properties> 11 <spring.version>4.2.4.RELEASE</spring.version> 12 <hibernate.version>5.0.7.Final</hibernate.version> 13 <slf4j.version>1.6.6</slf4j.version> 14 <springdatajpa.version>1.10.4.RELEASE</springdatajpa.version> 15 <c3p0.version>0.9.1.2</c3p0.version> 16 <junit.version>4.11</junit.version> 17 </properties> 18 19 <dependencies> 20 <!-- spring 框架 --> 21 <dependency> 22 <groupId>org.springframework</groupId> 23 <artifactId>spring-context</artifactId> 24 <version>${spring.version}</version> 25 </dependency> 26 27 <dependency> 28 <groupId>org.springframework</groupId> 29 <artifactId>spring-test</artifactId> 30 <version>${spring.version}</version> 31 </dependency> 32 33 34 <!-- spring data jpa 數據庫持久層 --> 35 <dependency> 36 <groupId>org.springframework.data</groupId> 37 <artifactId>spring-data-jpa</artifactId> 38 <version>${springdatajpa.version}</version> 39 </dependency> 40 41 <!-- hibernate 框架 --> 42 <dependency> 43 <groupId>org.hibernate</groupId> 44 <artifactId>hibernate-core</artifactId> 45 <version>${hibernate.version}</version> 46 </dependency> 47 <dependency> 48 <groupId>org.hibernate</groupId> 49 <artifactId>hibernate-entitymanager</artifactId> 50 <version>${hibernate.version}</version> 51 </dependency> 52 53 <!-- 數據庫鏈接池 --> 54 <dependency> 55 <groupId>c3p0</groupId> 56 <artifactId>c3p0</artifactId> 57 <version>${c3p0.version}</version> 58 </dependency> 59 60 <!-- 日誌框架 --> 61 <dependency> 62 <groupId>org.slf4j</groupId> 63 <artifactId>slf4j-log4j12</artifactId> 64 <version>${slf4j.version}</version> 65 </dependency> 66 <!-- 數據庫驅動 --> 67 <dependency> 68 <groupId>mysql</groupId> 69 <artifactId>mysql-connector-java</artifactId> 70 <version>5.1.6</version> 71 </dependency> 72 73 <!-- 單元測試 --> 74 <dependency> 75 <groupId>junit</groupId> 76 <artifactId>junit</artifactId> 77 <version>${junit.version}</version> 78 </dependency> 79 </dependencies> 80 81 </project>
在applicationContext.xml中增長以下配置ssh
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" 5 xmlns:jpa="http://www.springframework.org/schema/data/jpa" 6 xsi:schemaLocation=" 7 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd 9 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 10 http://www.springframework.org/schema/data/jpa 11 http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> 12 13 <!--指定鏈接池配置--> 14 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 15 <property name="driverClass" value="com.mysql.jdbc.Driver" /> 16 <property name="jdbcUrl" value="jdbc:mysql:///ssh01?useSSL=false" /> 17 <property name="user" value="root" /> 18 <property name="password" value="" /> 19 </bean> 20 <!-- spring整合JPA --> 21 <bean id="entityManagerFactory" 22 class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 23 <property name="dataSource" ref="dataSource" /> 24 <!--指定JPA掃描的實體類所在的包--> 25 <property name="packagesToScan" value="com.cenobitor.domain" /> 26 <!-- 指定持久層提供者爲Hibernate --> 27 <property name="persistenceProvider"> 28 <bean class="org.hibernate.ejb.HibernatePersistence" /> 29 </property> 30 <property name="jpaVendorAdapter"> 31 <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 32 <!-- 自動建表 --> 33 <property name="generateDdl" value="true" /> 34 <property name="database" value="MYSQL" /> 35 <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" /> 36 <property name="showSql" value="true" /> 37 </bean> 38 </property> 39 <property name="jpaDialect"> 40 <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" /> 41 </property> 42 </bean> 43 44 <!-- 配置事務管理器 --> 45 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 46 <property name="entityManagerFactory" ref="entityManagerFactory" /> 47 </bean> 48 49 <!-- 開啓事務註解 --> 50 <tx:annotation-driven transaction-manager="transactionManager" /> 51 <!--指定Spring Data JPA要進行掃描的包,該包中的類框架會自動爲其建立代理--> 52 <jpa:repositories base-package="com.cenobitor.dao" /> 53 54 </beans>
1 @Entity 2 @Table 3 public class User { 4 @Id 5 @GeneratedValue 6 @Column 7 private Integer id; 8 @Column 9 private String name; 10 @Column 11 private String password; 12 13 public Integer getId() { 14 return id; 15 } 16 17 public void setId(Integer id) { 18 this.id = id; 19 } 20 21 public String getName() { 22 return name; 23 } 24 25 public void setName(String name) { 26 this.name = name; 27 } 28 29 public String getPassword() { 30 return password; 31 } 32 33 public void setPassword(String password) { 34 this.password = password; 35 } 36 37 @Override 38 public String toString() { 39 return "User{" + 40 "id=" + id + 41 ", name='" + name + '\'' + 42 ", password='" + password + '\'' + 43 '}'; 44 } 45 }
1 // 泛型參數1 : 實體類 2 // 泛型參數2 : 實體類中主鍵的類型 3 @Repository 4 public interface JpaRepository extends org.springframework.data.jpa.repository.JpaRepository<User,Integer>{ 5 6 }
在com.cenobitor.test建立測試類,進行測試用例,若是在控制檯看到Hibernate輸出sql語句,說明操做成功
1 @RunWith(SpringJUnit4ClassRunner.class) 2 @ContextConfiguration("classpath:applicationContext.xml") 3 public class SpringDataJPATest { 4 @Autowired 5 private JpaRepository jpaRepository; 6 7 @Test 8 public void testQuery() { 9 // 查詢操做 10 List<User> list = jpaRepository.findAll(); 11 for (User user : list) { 12 System.out.println(user); 13 } 14 } 15 }
1 @Test 2 public void testSave() { 3 // 保存數據 4 User user = new User(); 5 user.setName("趙六"); 6 user.setPassword("1234"); 7 8 jpaRepository.save(user); 9 } 10 11 @Test 12 public void testUpdate() { 13 // 更新操做,傳入主鍵ID 14 User user = new User(); 15 user.setId(3); 16 user.setName("李四"); 17 // 調用該方法時,首先進行查詢操做,若是數據不存在,執行插入 18 // 若是數據存在,執行修改 19 jpaRepository.save(user); 20 } 21 22 @Test 23 public void testDelete() { 24 //刪除操做 25 jpaRepository.delete(3); 26 } 27 28 @Test 29 public void testFindOne() { 30 //根據主鍵進行查詢 31 User user = jpaRepository.findOne(4); 32 System.out.println(user); 33 }
JpaRepository支持接口規範方法名查詢。意思是若是在接口中定義的查詢方法符合它的命名規則,就能夠不用寫實現。
例如:findByName這個方法表示從數據庫中查詢Name這個屬性等於XXX的全部記 錄,相似於SQL語句:select*from xTablewherename=x這種形式 這段話有兩個重點:
①方法名須要在接口中設定
②必須符合必定的命名規範
find+全局修飾+By+實體的屬性名稱+限定詞+鏈接詞+.(其它實體屬性)+OrderBy+ 排序屬性+排序方向
例如:
findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(String firstName,StringlastName){.}
其中:Distinct是全局修飾(非必須),FirstName和LastName是實體的屬性名, And是鏈接詞,IgnoreCase是限定詞,Age是排序屬性,Desc是排序方向,限定詞 和鏈接詞統稱爲「關鍵詞」
1 // 泛型參數1 : 實體類 2 // 泛型參數2 : 實體類中主鍵的類型 3 @Repository 4 public interface JpaRepository extends org.springframework.data.jpa.repository.JpaRepository<User,Integer>{ 5 // =============標準命名方式=============== 6 // 根據名字進行精準查詢,Standard類中有name字段 7 User findByName(String name); 8 // 根據名字進行模糊查詢 9 User findByNameLike(String name); 10 // 查詢名字爲空的數據 11 List<User> findByNameIsNull(); 12 // 多條件查詢 13 User findByNameAndPassword(String name,String password); 14 // ==============非標準命名方式============= 15 // 使用JPQL進行非標準命名查詢 16 @Query("from User u where u.name like ?") 17 User findByNamexxxxxLikeJPQL(String name); 18 // 使用JPQL進行非標準多條件查詢 19 // 默認狀況下,問號的順序和傳入的參數順序是一致的 20 // 能夠在問號後面追加數字,改變和參數的匹配順序 21 // 下面的示例中,傳入的第一個參數匹配到第二個問號,傳入的第二個參數匹配到第一個問號 22 @Query("from User u where u.name like ?2 and password = ?1") 23 User findByNameAndOperatorJPQL(String password,String name); 24 // 使用標準SQL進行非標準命名查詢 25 @Query(value = "select * from user u where u.name like ?", nativeQuery = true) 26 User findByNamexxxxxLikeSQL(String name); 27 }
1 @Test 2 public void testFindByName(){ 3 User user = jpaRepository.findByName("趙六"); 4 System.out.println(user); 5 } 6 7 @Test 8 public void testFindByNameLike(){ 9 User user = jpaRepository.findByNameLike("%六"); 10 System.out.println(user); 11 } 12 13 @Test 14 public void testFindByNameIsNull(){ 15 List<User> users = jpaRepository.findByNameIsNull(); 16 System.out.println(users); 17 } 18 19 @Test 20 public void testFindByNameAndPassword(){ 21 User user = jpaRepository.findByNameAndPassword("趙六","1234"); 22 System.out.println(user); 23 } 24 25 @Test 26 public void testFindByNamexxxxxLikeJPQL(){ 27 User user = jpaRepository.findByNamexxxxxLikeJPQL("趙六"); 28 System.out.println(user); 29 } 30 31 @Test 32 public void testFindByNameAndOperatorJPQL(){ 33 User user = jpaRepository.findByNameAndOperatorJPQL("1234","趙六"); 34 System.out.println(user); 35 } 36 37 @Test 38 public void testFindByNamexxxxxLikeSQL(){ 39 User user = jpaRepository.findByNamexxxxxLikeSQL("趙六"); 40 System.out.println(user); 41 }
1 // ================自定義增刪改操做========== 2 @Transactional // 使用事務 3 @Modifying // 執行修改操做 4 @Query("delete from User u where u.name = ?") 5 void deleteByName(String name); 6 7 @Transactional 8 @Modifying // 執行修改操做 9 @Query("update User u set u.password = ?2 where u.name = ?1") 10 void updatePasswordByName(String name, String password);
1 @Test 2 public void testDeleteByName() { 3 // 使用JPQL進行自定義刪除操做 4 jpaRepository.deleteByName("趙六"); 5 } 6 7 @Test 8 public void testUpdatePasswordByName() { 9 // 使用JPQL進行自定義更新操做 10 jpaRepository.updatePasswordByName("趙六","333"); 11 }
1 //分頁查詢 2 @Test 3 public void TestPageQuery() throws IOException { 4 int page = 1 ; //當前頁面 5 int rows = 10 ; //每頁數據條數 6 //建立分頁條件 7 Pageable pageable = new PageRequest(page - 1, rows); 8 Page<User> page1 = jpaRepository.findAll(pageable); 9 //獲取總數據條數 10 long totalElements = page1.getTotalElements(); 11 //獲取結果集 12 List<User> list = page1.getContent(); 13 System.out.println(list); 14 15 }
@Repository public interface JpaRepository extends JpaRepository<User,Integer>, JpaSpecificationExecutor<User> { }
1 @RunWith(SpringJUnit4ClassRunner.class) 2 @ContextConfiguration("classpath:applicationContext.xml") 3 public class SpringDataJPATest { 4 @Autowired 5 private JpaRepository jpaRepository; 6 7 @Test 8 public void testConditionPageQuery() throws IOException { 9 10 User user = new User(); 11 user.setName("李%"); 12 user.setPassword("1234"); 13 14 int page = 1 ; //當前頁面 15 int rows = 10 ; //每頁數據條數 16 17 //構造查詢條件 18 Specification<User> specification = new Specification<User>() { 19 @Override 20 public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 21 /** 22 * 建立一個查詢的where語句 23 * @param root : 根對象.能夠簡單的認爲就是泛型對象 24 * @param cb : 構建查詢條件 25 * @return a {@link Predicate}, must not be {@literal null}. 26 */ 27 String name = user.getName(); 28 String password = user.getPassword(); 29 // 存儲條件的集合 30 ArrayList<Predicate> list = new ArrayList<>(); 31 if (! name.isEmpty()){ 32 //構建模糊查詢條件,參數2爲具體的比較的值 33 Predicate p1 = cb.like(root.get("name").as(String.class),name); 34 list.add(p1); 35 } 36 if (! password.isEmpty()){ 37 Predicate p2 = cb.equal(root.get("password").as(String.class), password); 38 list.add(p2); 39 } 40 if (list.size() == 0 ){ 41 return null; 42 } 43 Predicate[] arr = new Predicate[list.size()]; 44 list.toArray(arr); 45 return cb.and(arr); 46 } 47 48 }; 49 Pageable pageable = new PageRequest(page-1,rows); 50 Page<User> page1 = jpaRepository.findAll(specification,pageable); 51 List<User> content = page1.getContent(); 52 System.out.println(content); 53 } 54 }