在说它们之间的关系之前,先说一说 JPA 和 Hibernate。JPA 是 SUN 公司推出的一套基于 ORM 的规范,内部由一系列的接口和抽象类构成。而 Hibernate 是实现了 JPA 规范的框架,它封装了 JDBC,可以对数据库进行操作。SpringDataJPA 是 对 JPA 规范的进一步封装,它并没有实现 JPA 的操作,而真正对数据的增删改查还是要依赖 Hibernate 等框架。下面这一张图诠释了它们之间的关系:
我们在代码中使用的是 SpringDataJPA 提供给我们的方法,SpringDataJPA 封装了 JPA,它的方法中还需要调用 JPA 规范中定义的方法,而 JPA 是一些接口和抽象类,所以最终还是需要依赖 Hibernate 等实现了 JPA 规范的框架来对数据库进行操作。
1)首先需要导入坐标
要整合 Spring 和 SpringDataJPA,并且还需要提供 JPA 的服务提供者 HIbernate,所以需要导入 Spring、SpringDataJPA 相关坐标,Hibernate 相关坐标和数据库驱动坐标等。
<properties>
<spring.version>4.2.4.RELEASE</spring.version>
<hibernate.version>5.0.7.Final</hibernate.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<c3p0.version>0.9.1.2</c3p0.version>
<mysql.version>5.1.6</mysql.version>
</properties>
<dependencies>
<!-- junit单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<!-- spring beg -->
<!-- spring aop 相关 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring aop 相关 end -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring end -->
<!-- hibernate beg -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<!-- hibernate end -->
<!-- c3p0 beg -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- c3p0 end -->
<!-- log end -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- el beg 使用spring data jpa 必须引入 -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
<!-- el end -->
</dependencies>
2)SpringDataJPA 与 Spring 整合
Spring 整合其他框架最繁琐的就是配置文件,所以接下来要在配置文件中写一些关于 SpringDataJPA 的配置。
<!-- 1.创建entityManagerFactory对象交给spring容器管理 -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 扫描实体类 -->
<property name="packagesToScan" value="cn.itcast.domain"/>
<!-- jpa的实现厂家 -->
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
</property>
<!-- jpa的供应商适配器 -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!-- 是否创建表 -->
<property name="generateDdl" value="false" />
<!-- 使用的数据库 -->
<property name="database" value="MYSQL"/>
<!-- 使用的数据库方言 -->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
<!-- 是否显示SQL语句 -->
<property name="showSql" value="true"/>
</bean>
</property>
<!-- jpa的方言:一些高级的特性(如果不适用,不配置也可以) -->
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
</property>
</bean>
<!-- 2.配置数据库连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"/>
<property name="password" value="root"/>
<property name="jdbcUrl" value="jdbc:mysql:///jpa"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
</bean>
<!-- 3.整合spring dataJpa -->
<!--dao接口所在的包-->
<jpa:repositories base-package="cn.itcast.dao" transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
<!-- 4.配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<!-- 5.配置声明式事务 -->
<!-- 6.配置包扫描 -->
<context:component-scan base-package="cn.itcast" />
3)用注解建立实体和数据库表的映射关系
此步骤省略
4)编写符合 SpringDataJPA 规范的 Dao 层接口
符合 SpringDataJPA 规范,就是需要接口 实现 JpaRepository 和 JpaSpecificationExecutor 接口
public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer>
5)完成以上步骤之后,就可以使用定义好的 Dao 层接口完成基本的 CRUD 操作
@Test
public void testFindOne(){
Customer customer = customerDao.findOne(3L);
System.out.println(customer);
}
1)疑问
在使用 SpringDataJPA 时,一般实现 JpaRepository 和 JpaSpecificationExecutor 接口,这样就可以使用这些接口中定义的方法,但是这些方法都只是一些声明,没有具体的实现方式,那么在 SpringDataJPA 中它又是怎么实现的呢?
2)实现过程
我们以debug断点调试的方式,通过分析 SpringDataJPA 的源码来分析程序的执行过程,以上述的findOne方法为例进行分析
3)总结
SpringDataJPA 的执行过程是基于 JDK 的动态代理,1.通过 JdkDynamicAopProxy 的 invoke 方法创建了一个动态代理对象 SimpleJpaRepository;2.SimpleJpaRepository 当中封装了JPA的操作(借助JPA的api完成数据库的CRUD);3.通过 hibernate 完成数据库操作(封装了jdbc)
1)使用 SpringDataJPA 中接口定义的方法进行查询
在继承了 JpaRepository 和 JpaRepository 接口后,我们就可以使用接口中定义的方法进行查询
2)使用JPQL的方式查询
使用 SpringDataJPA 提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用 @Query 注解,结合 JPQL 的语句方式完成查询
@Query 注解的使用非常简单,只需在方法上面标注该注解,同时提供一个JPQL查询语句即可
public interface CustomerDao extends JpaRepository<Customer, Long>,JpaSpecificationExecutor<Customer> {
//@Query 使用jpql的方式查询。
@Query(value="from Customer")
public List<Customer> findAllCustomer();
//@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引
@Query(value="from Customer where custName = ?1")
public Customer findCustomer(String custName);
}
此外,也可以通过使用 @Query 来执行一个更新操作,为此,我们需要在使用 @Query 的同时,用 @Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询
@Query(value="update Customer set custName = ?1 where custId = ?2")
@Modifying
public void updateCustomer(String custName,Long custId);
3)使用 SQL 语句查询
Spring Data JPA同样也支持sql语句的查询,如下:
/**
* nativeQuery : 使用本地sql的方式查询
*/
@Query(value="select * from cst_customer",nativeQuery=true)
public void findSql();
4)使用 SpringDataJPA 提供的方法命名规则查询
顾名思义,方法命名规则查询就是根据方法的名字,就能创建查询。只需要按照Spring Data JPA提供的方法命名规则定义方法的名称,就可以完成查询工作。Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询。
按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。
//方法命名方式查询,不需要加 @Query 注解(根据客户名称查询客户)
public Customer findByCustName(String custName);