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,"安徽大别山");
<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>
<?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>
@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 }
//@Repository("studentDao") 这里不用加入IOC容器 Spring默认帮我们注入 public interface StudentDao extends JpaRepository<Student, Integer>, JpaSpecificationExecutor<Student> { /* JpaRepository<T,ID>:T:当前表的类型 ID:当前表主键字段类型 功能:用来完成基本的CRUD操作 ,因为内部定义了很多增删改查操作 JpaSpecificationExecutor<T>:T:当前表的类型 功能:用来完成复杂的查询等一些操作 */ }
@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 toPredicate Predicate[] p = new Predicate[list.size()]; query.where(cb.and