关于JPA总共写了三篇内容,下面附上链接:
JPA01:https://www.cnblogs.com/buwei/p/9979794.html
JPA02:https://www.cnblogs.com/buwei/p/9985287.html
JPA03:https://www.cnblogs.com/buwei/p/9985941.html
一、Spring Data JPA的概述
1.1 Spring Data JPA概述
Spring Data JPA是Spring基于ORM框架、JPA规范的基础上封装的一套JPA应用框架。他提供了包括增删改查在内的常用功能,且易于扩展。
Spring Data JPA让我们解脱了DAO的操作,基本上所有的CRUD都可以依赖于它来实现,在试驾的工程中,推荐使用Spring Data JPA+ORM(如:Hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦。
1.2 Spring Data JPA的特性
使用Spring Data JPA,我们的DAO层只需要写接口,就自动具有了增删改查、分页查询等方法。
1.3 Spring Data JPA与JPA和Hibernate之间的关系
JPA是一套规范,内部是由接口和抽象内组成,Hibernate是一套乘数的ORM框架,而且Hibernate实现了JPA规范,所以也可以称Hibernate是JPA的一种实现方式,我们使用JPA的API编程,是一种面向接口编程的思想。
二、Spring Data JPA的快速入门
2.1 需求说明
Spring Data JPA完成客户的基本CRUD操作
2.2 搭建Spring Data JPA的开发环境
1. 引入Spring Data JPA的坐标
使用Spring Data JPA,需要整合Spring与Spring Data JPA,并且需要提供JPA的服务提供者Hibernate,所以需要导入Spring相关坐标,Hibernate坐标,数据库驱动坐标等。
1 <properties> 2 <spring.version>4.2.4.RELEASE</spring.version> 3 <hibernate.version>5.0.7.Final</hibernate.version> 4 <slf4j.version>1.6.6</slf4j.version> 5 <log4j.version>1.2.12</log4j.version> 6 <c3p0.version>0.9.1.2</c3p0.version> 7 <mysql.version>5.1.6</mysql.version> 8 </properties> 9 <dependencies> 10 <!-- junit单元测试 --> 11 <dependency> 12 <groupId>junit</groupId> 13 <artifactId>junit</artifactId> 14 <version>4.9</version> 15 <scope>test</scope> 16 </dependency> 17 18 <!-- spring beg --> 19 <dependency> 20 <groupId>org.aspectj</groupId> 21 <artifactId>aspectjweaver</artifactId> 22 <version>1.6.8</version> 23 </dependency> 24 25 <dependency> 26 <groupId>org.springframework</groupId> 27 <artifactId>spring-aop</artifactId> 28 <version>${spring.version}</version> 29 </dependency> 30 31 <dependency> 32 <groupId>org.springframework</groupId> 33 <artifactId>spring-context</artifactId> 34 <version>${spring.version}</version> 35 </dependency> 36 37 <dependency> 38 <groupId>org.springframework</groupId> 39 <artifactId>spring-context-support</artifactId> 40 <version>${spring.version}</version> 41 </dependency> 42 43 <dependency> 44 <groupId>org.springframework</groupId> 45 <artifactId>spring-orm</artifactId> 46 <version>${spring.version}</version> 47 </dependency> 48 49 <dependency> 50 <groupId>org.springframework</groupId> 51 <artifactId>spring-beans</artifactId> 52 <version>${spring.version}</version> 53 </dependency> 54 55 <dependency> 56 <groupId>org.springframework</groupId> 57 <artifactId>spring-core</artifactId> 58 <version>${spring.version}</version> 59 </dependency> 60 <!-- spring end --> 61 62 <!-- hibernate beg --> 63 <dependency> 64 <groupId>org.hibernate</groupId> 65 <artifactId>hibernate-core</artifactId> 66 <version>${hibernate.version}</version> 67 </dependency> 68 <dependency> 69 <groupId>org.hibernate</groupId> 70 <artifactId>hibernate-entitymanager</artifactId> 71 <version>${hibernate.version}</version> 72 </dependency> 73 <dependency> 74 <groupId>org.hibernate</groupId> 75 <artifactId>hibernate-validator</artifactId> 76 <version>5.2.1.Final</version> 77 </dependency> 78 <!-- hibernate end --> 79 80 <!-- c3p0 beg --> 81 <dependency> 82 <groupId>c3p0</groupId> 83 <artifactId>c3p0</artifactId> 84 <version>${c3p0.version}</version> 85 </dependency> 86 <!-- c3p0 end --> 87 88 <!-- log end --> 89 <dependency> 90 <groupId>log4j</groupId> 91 <artifactId>log4j</artifactId> 92 <version>${log4j.version}</version> 93 </dependency> 94 95 <dependency> 96 <groupId>org.slf4j</groupId> 97 <artifactId>slf4j-api</artifactId> 98 <version>${slf4j.version}</version> 99 </dependency> 100 101 <dependency> 102 <groupId>org.slf4j</groupId> 103 <artifactId>slf4j-log4j12</artifactId> 104 <version>${slf4j.version}</version> 105 </dependency> 106 <!-- log end --> 107 108 109 <dependency> 110 <groupId>mysql</groupId> 111 <artifactId>mysql-connector-java</artifactId> 112 <version>${mysql.version}</version> 113 </dependency> 114 115 <dependency> 116 <groupId>org.springframework.data</groupId> 117 <artifactId>spring-data-jpa</artifactId> 118 <version>1.9.0.RELEASE</version> 119 </dependency> 120 121 <dependency> 122 <groupId>org.springframework</groupId> 123 <artifactId>spring-test</artifactId> 124 <version>4.2.4.RELEASE</version> 125 </dependency> 126 127 <!-- el beg 使用spring data jpa 必须引入 --> 128 <dependency> 129 <groupId>javax.el</groupId> 130 <artifactId>javax.el-api</artifactId> 131 <version>2.2.4</version> 132 </dependency> 133 134 <dependency> 135 <groupId>org.glassfish.web</groupId> 136 <artifactId>javax.el</artifactId> 137 <version>2.2.4</version> 138 </dependency> 139 <!-- el end --> 140 </dependencies>
2. 整合Spring Data JPA与JPA
创建applicationContext.xml配置文件
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" xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" 6 xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task" 7 xsi:schemaLocation=" 8 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 9 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 10 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 11 http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd 12 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 13 http://www.springframework.org/schema/data/jpa 14 http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> 15 16 <!-- 1.dataSource 配置数据库连接池--> 17 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 18 <property name="driverClass" value="com.mysql.jdbc.Driver" /> 19 <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_jpa" /> 20 <property name="user" value="root" /> 21 <property name="password" value="root" /> 22 </bean> 23 24 <!-- spring和spring data jpa的配置 --> 25 <!-- 2.配置entityManagerFactory对象交个spring容器管理 --> 26 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 27 <property name="dataSource" ref="dataSource" /> 28 <!-- 配置要扫描的包(实体类所在的包)--> 29 <property name="packagesToScan" value="com.buwei.domain" /> 30 <!-- jpa的实现厂商 --> 31 <property name="persistenceProvider"> 32 <bean class="org.hibernate.jpa.HibernatePersistenceProvider" /> 33 </property> 34 <!--JPA的供应商适配器--> 35 <property name="jpaVendorAdapter"> 36 <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 37 <!-- 配置是否自动创建数据库表 --> 38 <property name="generateDdl" value="false" /> 39 <!-- 指定数据库类型 --> 40 <property name="database" value="MYSQL" /> 41 <!-- 数据库方言,支持的特有语法 --> 42 <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" /> 43 <!-- 是否显示sql--> 44 <property name="showSql" value="true" /> 45 </bean> 46 </property> 47 48 <!-- jpa的方言:高级特性 --> 49 <property name="jpaDialect"> 50 <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" /> 51 </property> 52 53 <!--注入jpa的配置信息 54 加载jpa的基本配置信息和jpa实现方式(hibernate)的配置信息 55 hibernate.hbm2ddl.auto : 自动创建数据库表 56 create : 每次都会重新创建数据库表 57 update:有表不会重新创建,没有表会重新创建表 58 none:不创建表 59 --> 60 <property name="jpaProperties" > 61 <props> 62 <prop key="hibernate.hbm2ddl.auto">update</prop> 63 </props> 64 </property> 65 66 </bean> 67 <!-- 3.事务管理器--> 68 <!-- JPA事务管理器 --> 69 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 70 <property name="entityManagerFactory" ref="entityManagerFactory" /> 71 </bean> 72 73 <!-- 整合spring data jpa--> 74 <jpa:repositories base-package="com.buwei.mapper" transaction-manager-ref="transactionManager" 75 entity-manager-factory-ref="entityManagerFactory"></jpa:repositories> 76 77 <!-- 4.txAdvice--> 78 <tx:advice id="txAdvice" transaction-manager="transactionManager"> 79 <tx:attributes> 80 <tx:method name="save*" propagation="REQUIRED"/> 81 <tx:method name="insert*" propagation="REQUIRED"/> 82 <tx:method name="update*" propagation="REQUIRED"/> 83 <tx:method name="delete*" propagation="REQUIRED"/> 84 <tx:method name="get*" read-only="true"/> 85 <tx:method name="find*" read-only="true"/> 86 <tx:method name="*" propagation="REQUIRED"/> 87 </tx:attributes> 88 </tx:advice> 89 90 <!-- 5.aop--> 91 <aop:config> 92 <aop:pointcut id="pointcut" expression="execution(* com.buwei.service.*.*(..))" /> 93 <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" /> 94 </aop:config> 95 96 <!-- 6.配置包扫描 --> 97 <context:component-scan base-package="com.buwei"></context:component-scan> 98 99 <!--组装其它 配置文件--> 100 101 </beans>
3. 使用JPA注解配置映射关系
1 /** 2 * 所有的注解都是使用JPA的规范提供的注解, 3 * 所以在导入注解包的时候,一定要导入javax.persistence下的 4 */ 5 @Entity //声明实体类 6 @Table(name="cst_customer") //建立实体类和表的映射关系 7 public class Customer implements Serializable { 8 @Id//声明当前私有属性为主键 9 @GeneratedValue(strategy= GenerationType.IDENTITY) //配置主键的生成策略 10 @Column(name="cust_id") //指定和表中cust_id字段的映射关系 11 private Long custId; 12 13 @Column(name="cust_name") //指定和表中cust_name字段的映射关系 14 private String custName; 15 16 @Column(name="cust_source")//指定和表中cust_source字段的映射关系 17 private String custSource; 18 19 @Column(name="cust_industry")//指定和表中cust_industry字段的映射关系 20 private String custIndustry; 21 22 @Column(name="cust_level")//指定和表中cust_level字段的映射关系 23 private String custLevel; 24 25 @Column(name="cust_address")//指定和表中cust_address字段的映射关系 26 private String custAddress; 27 28 @Column(name="cust_phone")//指定和表中cust_phone字段的映射关系 29 private String custPhone; 30 31 //省略getter和setter方法 32 }
2.3 使用Spring Data JPA完成需求
1. 编写符合Spring Data JPA规范的Dao层接口
Spring Data JPA是spring提供的一款对于数据访问层(DAO)的框架,使用Spring Data JPA,只需要按照框架的规范提供DAO接口,不需要实现类就可以完成数据库的增删改查、分页查询等方法的定义。
在Spring Data JPA中,对于定义符合规范的DAO接口,我们只需要遵循以下几点就可以了:
1.创建一个DAO层接口,并实现JapReponsitory和JpaSpecificationExecutor
2.提供相应的泛型
1 /** 2 * JpaRepository<实体类类型,主键类型>:用来完成基本CRUD操作 3 * JpaSpecificationExecutor<实体类类型>:用于复杂查询(分页等查询操作) 4 */ 5 public interface CustomerDAO extends 6 JpaRepository<Customer, Long>,JpaSpecificationExecutor<Customer> { 7 8 }
2.编写测试类完成基本CRUD操作
1 @RunWith(SpringJUnit4ClassRunner.class) 2 @ContextConfiguration(locations = "classpath:applicationContext.xml") 3 public class CustomerDaoTest { 4 @Autowired 5 private CustomerDAO customerDao; 6 7 /** 8 * 保存:调用save(obj)方法 9 * 对于save方法,当执行此方法的对象中id无值,及为新增操作 10 */ 11 @Test 12 public void testInsert(){ 13 // 创建一个新的用户 14 Customer customer = new Customer(); 15 customer.setCustName("不为"); 16 // 新增 17 customerDao.save(customer); 18 } 19 20 /** 21 * 根据ID查询:调用findOne方法 22 */ 23 @Test 24 public void testFindById(){ 25 Customer customer = customerDao.findOne(1L); 26 System.out.println(customer); 27 } 28 29 /** 30 * 修改:调用save(obj)方法 31 * 对于save方法,当执行此方法的对象中id有值,及为更新操作 32 */ 33 @Test 34 public void testUpdate(){ 35 // 查询id为1的用户 36 Customer customer = customerDao.findOne(1L); 37 // 修改客户名称 38 customer.setCustName("不为——为"); 39 // 更新 40 customerDao.save(customer); 41 } 42 43 /** 44 * 根据id删除:调用delete(id)方法 45 */ 46 @Test 47 public void testDelete(){ 48 customerDao.delete(1L); 49 } 50 }
三、Spring Data JPA的内部原理剖析
3.1 Spring Data JPA的常用接口分析
在上面的案例中,我们发现对于customerDao,我们并没有提供任何方法就可以调用增删改查方法,是因为接口继承了JpaReponsitory和JpaSpecificationExecutor,我们使用的方法就是上面两个接口中的方法。
3.2 Spring Data JPA的实现过程
等理解清楚了再来作补充。。。。也欢迎大家留言。。。。
四、Spring Data JPA的查询方式
4.1 使用Spring DataJPA中接口定义的方法进行查询
上面用到的方法直接使用了JpaReponsitory与JpaSpecificationExecutor接口中的方法,源码如下:
1 @NoRepositoryBean 2 public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> { 3 List<T> findAll(); 4 5 List<T> findAll(Sort var1); 6 7 List<T> findAll(Iterable<ID> var1); 8 9 <S extends T> List<S> save(Iterable<S> var1); 10 11 void flush(); 12 13 <S extends T> S saveAndFlush(S var1); 14 15 void deleteInBatch(Iterable<T> var1); 16 17 void deleteAllInBatch(); 18 19 T getOne(ID var1); 20 }
1 public interface JpaSpecificationExecutor<T> { 2 T findOne(Specification<T> var1); 3 4 List<T> findAll(Specification<T> var1); 5 6 Page<T> findAll(Specification<T> var1, Pageable var2); 7 8 List<T> findAll(Specification<T> var1, Sort var2); 9 10 long count(Specification<T> var1); 11 }
4.2 使用JPQL的方式查询
使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于有些业务,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL语句完成查询。
@Query注解的使用非常简单,只需要在方法上面标注该注解,同时童工一个JPQL查询语句即可。
1 public interface CustomerDAO extends 2 JpaRepository<Customer, Long>,JpaSpecificationExecutor<Customer> { 3 4 /** 5 * @Query 使用jpql的方式查询。 6 */ 7 @Query(value="from Customer") 8 public List<Customer> findAllCustomer(); 9 10 /** 11 * @Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引 12 * @param custName 13 * @return 14 */ 15 @Query(value="from Customer where custName = ?1") 16 public Customer findCustomer(String custName); 17 18 /** 19 * @Modifying是标识该操作为修改查询操作 20 * @param custName 21 * @param custId 22 */ 23 @Query(value="update Customer set custName = ?1 where custId = ?2") 24 @Modifying 25 public void updateCustomer(String custName,Long custId); 26 }
4.3 使用SQL语句查询
使用SQL语句查询如下:
1 /** 2 * nativeQuery : 标识使用本地sql的方式查询 3 */ 4 @Query(value="select * from cst_customer",nativeQuery=true) 5 public void findBySql();
4.4 方法命名规则查询
按照Spring Data JPA定义的规则,查询方法一FindBy开头,设计条件查询时,条件的属性用条件关键词连接,方法名命名需符合小驼峰规则,框架会自动对方法名进行解析。
1 /** 2 * 方法命名方式查询(根据客户名称查询客户) 3 * @param custName 4 * @return 5 */ 6 public Customer findByCustName(String custName);
对应的具体的关键字适用方法和对应的SQL如下表所示
Keyword | Sample | JPQL |
|
|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
|
|
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
|
|
Is,Equals | findByFirstnameIs, findByFirstnameEquals | … where x.firstname = ?1 |
|
|
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
|
|
LessThan | findByAgeLessThan | … where x.age < ?1 |
|
|
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
|
|
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
|
|
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
|
|
After | findByStartDateAfter | … where x.startDate > ?1 |
|
|
Before | findByStartDateBefore | … where x.startDate < ?1 |
|
|
IsNull | findByAgeIsNull | … where x.age is null |
|
|
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
|
|
Like | findByFirstnameLike | … where x.firstname like ?1 |
|
|
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
|
|
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
|
|
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
|
|
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
|
|
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
|
|
Not | findByLastnameNot | … where x.lastname <> ?1 |
|
|
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
|
|
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
|
|
TRUE | findByActiveTrue() | … where x.active = true |
|
|
FALSE | findByActiveFalse() | … where x.active = false |
|
|
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
|
|