Spring Data JPA入门及深入

Posted 蚂蚁小哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Data JPA入门及深入相关的知识,希望对你有一定的参考价值。

一:Spring Data JPA简介

  Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!

  Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现,在实际的工作工程中,推荐使用Spring Data JPA + ORM(如:hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦

1:Spring Data JPA与JPA和hibernate三者关系

  我在接下面的文章中都对它们三者进行扩展及应用,以及三者的封装关系及调用关系,我下面也会以一张图说明,如果此时有对JPA还一窍不通的可以参考我之前的一篇关于JPA文章的介绍

  关系:其实看三者框架中,JPA只是一种规范,内部都是由接口和抽象类构建的;hibernate它是我们最初使用的一套由ORM思想构建的成熟框架,但是这个框架内部又实现了一套JPA的规范(实现了JPA规范定义的接口),所有也可以称hibernate为JPA的一种实现方式我们使用JPA的API编程,意味着站在更高的角度上看待问题(面向接口编程);Spring Data JPA它是Spring家族提供的,对JPA规范有一套更高级的封装,是在JPA规范下专门用来进行数据持久化的解决方案。

   其实规范是死的,但是实现厂商是有很多的,这里我对hibernate的实现商介绍,如其它的实现厂商大家可以自行去理解,因为规范在这,实现类可以更好别的,面向接口编程。

二:SpringDataJPA快速入门(完成简单CRUD)

1:环境搭建及简单查询

-- 删除库
-- drop database demo_jpa;
-- 创建库
create database if not exists demo_jpa charset gbk collate gbk_chinese_ci;
-- 使用库
use demo_jpa;
-- 创建表
create table if not exists student(
    sid int primary key auto_increment,     -- 主键id
    sname varchar(10) not null,             -- 姓名
    sage tinyint unsigned default 22,        -- 年龄
    smoney decimal(6,1),                    -- 零花钱
    saddress varchar(20)                    -- 住址
)charset gbk collate gbk_chinese_ci;
insert into student values
(1,"蚂蚁小哥",23,8888.8,"安徽大别山"),
(2,"王二麻",22,7777.8,"安徽大别山"),
(3,"李小二",23,6666.8,"安徽大别山"),
(4,"霍元甲",23,5555.8,null),
(5,"叶问",22,4444.8,"安徽大别山"),
(6,"李连杰",23,3333.8,"安徽大别山"),
(7,"马克思",20,2222.8,"安徽大别山");
mysql简单建表语句   重要【后面都参照这个建表语句进行】
<dependencies>
        <!--单元测试坐标  4.12为最稳定-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <!--Spring核心坐标  注:导入此坐标也同时依赖导入了一些其它jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <!--Spring对事务管理坐标-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <!--Spring整合ORM框架的必须坐标 如工厂/事务等交由Spring管理-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <!--Spring单元测试坐标-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <!--Spring Data JPA 核心坐标-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.10.4.RELEASE</version>
        </dependency>
        <!--导入AOP切入点表达式解析包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>

        <!--Hibernate核心坐标-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.10.Final</version>
        </dependency>
        <!--hibernate对持久层的操作坐标-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.4.10.Final</version>
        </dependency>

        <!--这下面的2个el坐标是使用Spring data jpa 必须导入的,不导入则报el异常-->
        <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>

        <!--C3P0连接池坐标-->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <!--MySQL驱动坐标-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>

        <!--JAXB API是java EE 的API,因此在java SE 9.0 中不再包含这个 Jar 包。
            java 9 中引入了模块的概念,默认情况下,Java SE中将不再包含java EE 的Jar包
            而在 java 6/7 / 8 时关于这个API 都是捆绑在一起的
            抛出:java.lang.ClassNotFoundException: javax.xml.bind.JAXBException异常加下面4个坐标
            -->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
    </dependencies>
pom.xml坐标导入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/data/jpa
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <!--配置注解扫描-->
    <context:component-scan base-package="cn.xw"></context:component-scan>

    <!--配置C3P0连接池-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/demo_jpa"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123"></property>
    </bean>

    <!--创建EntityManagerFactory交给Spring管理,让Spring生成EntityManager实体管理器操作JDBC-->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <!--配置一个连接池,后期获取连接的Connection连接对象-->
        <property name="dataSource" ref="dataSource"></property>
        <!--配置要扫描的包,因为ORM操作是基于实体类的-->
        <property name="packagesToScan" value="cn.xw.domain"></property>
        <!--配置JPA的实现厂家 实现了JPA的一系列规范-->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
        </property>
        <!--JPA供应商适配器 因为我上面使用的是hibernate,所有适配器也选择hibernate-->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--指定当前操作的数据库类型 必须大写,底层是一个枚举类-->
                <property name="database" value="MYSQL"></property>
                <!--是否自动创建数据库表-->
                <property name="generateDdl" value="false"></property>
                <!--是否在运行的时候 在控制台打印操作的SQL语句-->
                <property name="showSql" value="true"></property>
                <!--指定数据库方言:支持的语法,如Oracle和Mysql语法略有不同 org.hibernate.dialect下面的类就是支持的语法-->
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"></property>
                <!--设置是否准备事务休眠会话的底层JDBC连接,即是否将特定于事务的隔离级别和/或事务的只读标志应用于底层JDBC连接。-->
                <property name="prepareConnection" value="false"></property>
            </bean>
        </property>
        <!--JPA方言:高级特性 我下面配置了hibernate对JPA的高级特性 如一级/二级缓存等功能-->
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
        </property>
        <!--注入JPA的配置信息
            加载JPA的基本配置信息和JPA的实现方式(hibernate)的配置信息
            hibernate.hbm2ddl.auto:自动创建数据库表
                create:每次读取配置文件都会创建数据库表
                update:有则不做操作,没有则创建数据库表 -->
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <!--配置事务管理器  不同的事务管理器有不同的类 如我们当初使用这个事务管理器DataSourceTransactionManager-->
    <bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <!--把配置好的EntityManagerFactory对象交由Spring内部的事务管理器-->
        <property name="entityManagerFactory" ref="entityManagerFactory"></property>
        <!--因为entityManagerFactory内部设置数据库连接了  所有后面不用设置-->
        <!--<property name="dataSource" ref="dataSource"></property>-->
    </bean>

    <!--配置tx事务-->
    <tx:advice id="txAdvice" transaction-manager="jpaTransactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED" read-only="false"/>
            <tx:method name="insert*" propagation="REQUIRED" read-only="false"/>
            <tx:method name="update*" propagation="REQUIRED" read-only="false"/>
            <tx:method name="delete*" propagation="REQUIRED" read-only="false"/>
            <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
            <!--如果命名规范直接使用下面2行控制事务-->
            <!--<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>-->
            <!--<tx:method name="*" propagation="REQUIRED" read-only="false"/>-->
        </tx:attributes>
    </tx:advice>

    <!--配置AOP切面-->
    <aop:config>
        <!--在日常业务中配置事务处理的都是Service层,因为这里是案例讲解,所有我直接在测试类进行
            所有我把事务配置这,也方便后期拷贝配置到真项目中-->
        <aop:pointcut id="pt1" expression="execution(* cn.xw.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
    </aop:config>

    <!--整合SpringDataJPA-->
    <!--base-package:指定持久层接口
        entity-manager-factory-ref:引用其实体管理器工厂
        transaction-manager-ref:引用事务    -->
    <jpa:repositories base-package="cn.xw.dao" entity-manager-factory-ref="entityManagerFactory"
                      transaction-manager-ref="jpaTransactionManager"></jpa:repositories>
</beans>
applicationContext.xml 配置文件(重要)
@Entity
@Table(name = "student")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "sid")
    private Integer id;
    @Column(name = "sname")
    private String name;
    @Column(name = "sage")
    private Integer age;
    @Column(name = "smoney")
    private Double money;
    @Column(name = "saddress")
    private String address;
    //下面get/set/构造/toString都省略
    //注意:我上面的都使用包装类,切记要使用包装类,
    // 原因可能数据库某个字段查询出来的值为空 null    
}
Student实体类及映射关系
//@Repository("studentDao") 这里不用加入IOC容器 Spring默认帮我们注入
public interface StudentDao extends JpaRepository<Student, Integer>, JpaSpecificationExecutor<Student> {
    /*
    JpaRepository<T,ID>:T:当前表的类型  ID:当前表主键字段类型 
        功能:用来完成基本的CRUD操作 ,因为内部定义了很多增删改查操作
    JpaSpecificationExecutor<T>:T:当前表的类型
        功能:用来完成复杂的查询等一些操作
    */
}
StudentDao接口
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class Client {
    //注入数据
    @Autowired
    @Qualifier(value = "studentDao")
    private StudentDao sd;

    @Test
    public void test() {
        //查询id为4学生
        Student student = sd.findOne(4);
        System.out.println("开始打印:" + student);
        //以上是关于Spring Data JPA入门及深入的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data 系列 Spring+JPA(spring-data-commons)

Spring Data JPA入门

深入浅出学Spring Data JPA toPredicate Predicate[] p = new Predicate[list.size()]; query.where(cb.and

spring-data-jpa快速入门——

Spring Data 系列 Spring+JPA入门

spring data jpa详解