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 }