Spring Data JPA入门
1. Spring Data JPA是什么
它是Spring基于ORM框架、JPA规范封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展。学习并使用Spring Data JPA可以极大提高开发效率。
2. Spring Data JPA 有什么
主要看看Spring Data JPA 提供的编程接口
- Repository:最顶层的接口,是一个空接口,目的是为了统一所有的Repository的类型,且能让组件扫描时自动识别。
- CrudRepository: Repository的子接口,提供CRUD的功能。
- PagingAndSortingRepository: CrudRepository的子接口, 添加分页排序。
- JpaRepository: PagingAndSortingRepository的子接口,增加批量操作等。
- JpaSpecificationExecutor: 用来做复杂查询的接口。
接口继承关系图
3. 利用Spring Data JPA建立简单的用户管理项目
3.1 搭建项目
3.1.1 数据库建表
3.1.2 用户管理工程包结构
- com.zang.usermanage.repository (存放自定义的数据操作接口)
- com.zang.usermanage.model(存放实体模型)
- com.zang.usermanage.service(存放服务层的接口和实现)
- com.zang.usermanage.controller (如果是MVC项目可建立此包,存放控制器)
- com.zang.usermanage.exception(存放异常类)
- com.zang.usermanage.test(存放测试类)
3.1.3 所有需要的jar包
- Spring 基础jar包(版本:4.1.5)
- Spring Data Commons jar包(版本:1.9.2)
- Spring Data JPA jar包(版本:1.7.2)
- Hibernate 相关 jar包(版本:4.2.0)
- MySQL数据库连接包 (版本:5.1.21)
- 日志相关jar包
- 其它jar包
3.1.4 配置与编码
创建配置
配置文件一:applicationContext.xml(Spring上下文)
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"
default-lazy-init="true"> <!--第一步-->
<!--定义服务层代码存放的包扫描路径-->
<context:component-scan base-package="com.zang.usermanage.service" /> <!--第二步-->
<!--定义实体的工厂bean-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="userPU" />
<property name="persistenceXmlLocation" value="classpath:persistence.xml"></property>
</bean> <!--第三步-->
<!--定义事务管理器-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean> <!--第四步-->
<!--定义repository接口的存放目录-->
<!--定义接口实现的后缀,通常用Impl-->
<!--定义实体工厂的引用-->
<!--定义事务管理器的引用-->
<jpa:repositories base-package="com.zang.usermanage.repository"
repository-impl-postfix="Impl"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"/> <!--第五步-->
<!--声明采用注解的方式申明事务-->
<tx:annotation-driven transaction-manager="transactionManager"/> </beans>
配置文件二:persistence.xml(管理持久化)
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="userPU" transaction-type="RESOURCE_LOCAL">
<!--jpa的提供者-->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<!--声明数据库连接的驱动-->
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<!--jdbc数据库的连接地址-->
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/user_manage"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="123"/>
<!--配置方言-->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<!--激活查询日志功能-->
<property name="hibernate.show_sql" value="true"/>
<!--优雅地输出Sql-->
<property name="hibernate.format_sql" value="true"/>
<!--添加一条解释型标注-->
<property name="hibernate.use_sql_comments" value="false"/>
<!--配置如何根据java模型生成数据库表结构,常用update,validate-->
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
创建类文件并编码
User.java(用户实体类),UserRepository.java(用户的数据接口,继承JpaRepository接口), UserService.java(用户服务接口),UserServiceImpl.java(接口实现), UserNotFound.java(异常类,在查询实体未找到时抛出)
类之间关系
User.java(用户实体类)
package com.zang.usermanage.model; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table; /*
实体中常用的注解:
@Entity :声明这个类是一个实体类
@Table:指定映射到数据库的表格
@Id :映射到数据库表的主键属性,一个实体只能有一个属性被映射为主键
@GeneratedValue:主键的生成策略
*/
@Entity
@Table(name="user")
public class User { @Id
@GeneratedValue
private Integer id;
private String name;
private String address;
private String phone; public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
} }
UserRepository.java(用户的数据接口)
package com.zang.usermanage.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.zang.usermanage.model.User; public interface UserRepository extends JpaRepository<User,Integer> { }
3.2 实现简单的增、删、改、查
JpaRepository接口方法:
- delete删除或批量删除
- findAll查找所有
- findOne查找单个
- save保存单个或批量保存
- saveAndFlush保存并刷新到数据库
接口源码如下:(实现类为org.springframework.data.jpa.repository.support.SimpleJpaRepository.class)
package org.springframework.data.jpa.repository; import java.io.Serializable;
import java.util.List;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository; @NoRepositoryBean
public abstract interface JpaRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID>
{
public abstract List<T> findAll(); public abstract List<T> findAll(Sort paramSort); public abstract List<T> findAll(Iterable<ID> paramIterable); public abstract <S extends T> List<S> save(Iterable<S> paramIterable); public abstract void flush(); public abstract <S extends T> S saveAndFlush(S paramS); public abstract void deleteInBatch(Iterable<T> paramIterable); public abstract void deleteAllInBatch(); public abstract T getOne(ID paramID);
}
3.2.1 编码实现
UserService.java(用户服务接口)
package com.zang.usermanage.service; import java.util.List;import com.zang.usermanage.exception.UserNotFound;
import com.zang.usermanage.model.User; public interface UserService {
//添加用户
public void addUser(User user);
//修改用户
public User updateUser(User user) throws UserNotFound;
//删除用户,根据用户编号删除
public User deleteUser(int id) throws UserNotFound;
//查询单个用户
public User getUser(int id);
//查询所有用户
public List<User> getUsers();
}
UserServiceImpl.java(接口实现)
package com.zang.usermanage.service; import java.util.ArrayList;
import java.util.List; import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service; import com.zang.usermanage.exception.UserNotFound;
import com.zang.usermanage.model.User;
import com.zang.usermanage.repository.UserRepository; @Service("userService")
public class UserServiceImpl implements UserService { //自动装配
@Autowired
private UserRepository userRepository; //增加用户调用save方法
@Override
public void addUser(User user) {
userRepository.save(user);
} //更新用户先进行非空判断,再对新用户各个属性进行非空判断并赋值,最后调用save方法
//自定义异常类 UserNotFound
@Override
public User updateUser(User user) throws UserNotFound {
User userUpdate = userRepository.findOne(user.getId());
if (userUpdate==null)
throw new UserNotFound();
if (user.getName()!=null)
userUpdate.setName(user.getName());
if (user.getAddress()!=null)
userUpdate.setAddress(user.getAddress());
if (user.getPhone()!=null)
userUpdate.setPhone(user.getPhone());
userRepository.save(userUpdate);
return userUpdate;
} //删除用户先进行非空判断,最后调用delete方法
@Override
public User deleteUser(int id) throws UserNotFound {
User userDelete = userRepository.findOne(id);
if (userDelete==null)
throw new UserNotFound();
userRepository.delete(userDelete);
return userDelete;
} //查询单个,调用findOne方法
@Override
public User getUser(int id) { return userRepository.findOne(id);
} //查询所有,调用findAll方法
@Override
public List<User> getUsers() { return userRepository.findAll();
} }
3.2.2 测试
Client.java(测试类)
package com.zang.usermanage.test; import java.util.List; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page; import com.zang.usermanage.exception.UserNotFound;
import com.zang.usermanage.model.User;
import com.zang.usermanage.service.UserService; public class Client { public static void printUser(User user){
StringBuilder sb = new StringBuilder();
sb.append("id="+user.getId());
sb.append("name="+user.getName());
sb.append("address="+user.getAddress());
sb.append("phone="+user.getPhone());
System.out.println(sb.toString());
} public static void testList(UserService userService){
List<User> users = userService.getUsers();
if (users!=null){
for (int i=0; i<users.size();i++){
printUser(users.get(i));
}
}
}
public static void testUpate(UserService userService) throws UserNotFound{
User user = new User();
user.setId(1);
user.setAddress("北京路121号");
userService.updateUser(user);
testList(userService);
} public static void testAdd(UserService userService){
User user = new User();
user.setAddress("天河路120号");
user.setName("小徐");
user.setPhone("130000000");
userService.addUser(user);
testList(userService);
} public static void testDelete(UserService userService) throws UserNotFound{
userService.deleteUser(7);
testList(userService);
} public static void main(String[] arg) throws UserNotFound{ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) ac.getBean("userService");
//testList(userService);
testUpate(userService);
//testAdd(userService);
//testDelete(userService);
}
}
3.3 实现复杂查询
3.3.1 基于方法名解析的概念
JpaRepository支持接口规范方法名查询。意思是如果在接口中定义的查询方法符合它的命名规则,就可以不用写实现。
例如:findByName这个方法表示从数据库中查询Name这个属性等于XXX的所有记录,类似于SQL语句:select * from xxTable where name=xxx这种形式
这段话有两个重点:
- 方法名需要在接口中设定
- 必须符合一定的命名规范
3.3.2 方法名构造方法
find+全局修饰+By+实体的属性名称+限定词+连接词+ ...(其它实体属性)+OrderBy+排序属性+排序方向 例如:findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(String firstName,String lastName){......}
其中:Distinct是全局修饰(非必须),FirstName和LastName是实体的属性名,And是连接词,IgnoreCase是限定词,Age是排序属性,Desc是排序方向,限定词和连接词统称为“关键词”。
3.3.3 目前支持的关键词
常用词如下:
- 全局修饰:Distinct,Top,First
- 关键词:IsNull,IsNotNull,Like,NotLike,Containing,In,NotIn,IgnoreCase,Between,Equals,LessThan,GreaterThan,After,Before...
- 排序方向:Asc,Desc
- 连接词:And,Or
更多关键词请查看官方在线文档: https://docs.spring.io/spring-data/jpa/docs/2.0.4.RELEASE/reference/html/
3.3.4 嵌套实体方法命名规则
构词法:主实体中子实体的名称+ _ +子实体的属性名称
例如:List<Person> findByAddress_ZipCode(ZipCode zipCode) 表示查询所有 Address(地址)的zipCode(邮编)为指定值的所有Person(人员)
3.3.5 代码展示条件查询、分页、排序
UserRepository接口定义查询方法
package com.zang.usermanage.repository; import java.util.List; import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import com.zang.usermanage.model.User; public interface UserRepository extends JpaRepository<User,Integer> { //查询需求: 从数据库中查询电话号码(phone)以指定字符串开始(例如:136)的,并且地址(address)中包含指定字符串(例如:路)的记录 提取前两条,降序排列
//select * from user where phone like '136%' and address like '%路%' order by phone desc limit 0,2
List<User> findTop2ByPhoneStartingWithAndAddressContainingOrderByPhoneDesc(String phone,String address);
List<User> findTop2ByPhoneStartingWithAndAddressContaining(String phone,String address,Sort sort); //分页要用到Pageable接口
Page<User> findByPhoneStartingWithAndAddressContaining(String phone,String address,Pageable pageable); }
UserService.java
package com.zang.usermanage.service; import java.util.List; import org.springframework.data.domain.Page; import com.zang.usermanage.exception.UserNotFound;
import com.zang.usermanage.model.User; public interface UserService { //不分页带条件查询
public List<User> getUsersByConditionNoPage(String phone,String address); //带分页条件查询(需要得到用户列表并且得到分页信息)
public Page<User> getUsersByConditionWithPage(String phone,String address,Integer page,Integer pageSize);
//带分页条件查询(得到用户列表)
//public List<User> getUsersByCondition(String phone,String address,Integer page,Integer pageSize);
}
UserServiceImpl.java
package com.zang.usermanage.service; import java.util.ArrayList;
import java.util.List; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.stereotype.Service; import com.zang.usermanage.exception.UserNotFound;
import com.zang.usermanage.model.User;
import com.zang.usermanage.repository.UserRepository; @Service("userService")
public class UserServiceImpl implements UserService { //自动装配
@Autowired
private UserRepository userRepository; @Override
public Page<User> getUsersByConditionWithPage(String phone,String address,Integer page,Integer pageSize) { //不排序
Page<User> userPage = userRepository.findByPhoneStartingWithAndAddressContaining(phone,address,new PageRequest(page, pageSize)); //排序(三种方法) //第一种排序方式
//Page<User> userPage = userRepository.findByPhoneStartingWithAndAddressContaining(phone,address,new PageRequest(page, pageSize,new Sort(Direction.ASC,"name","phone"))); //第二种排序方式
//Order order = new Order(Direction.ASC,"phone");
//Page<User> userPage = userRepository.findByPhoneStartingWithAndAddressContaining(phone,address,new PageRequest(page, pageSize,new Sort(order)); //第三种排序方式
//List<Order> orders = new ArrayList<Order>();
//orders.add(new Order(Direction.DESC,"name"));
//orders.add(new Order(Direction.ASC,"phone"));
//Page<User> userPage = userRepository.findByPhoneStartingWithAndAddressContaining(phone,address,new PageRequest(page, pageSize,new Sort(orders)); return userPage; } /**
* 不分页
*/
@Override
public List<User> getUsersByConditionNoPage(String phone,String address) { return userRepository.findTop2ByPhoneStartingWithAndAddressContainingOrderByPhoneDesc(phone, address); //return userRepository.findTop2ByPhoneStartingWithAndAddressContaining(phone, address, new Sort(Direction.ASC,"phone")); //Order order = new Order(Direction.ASC,"phone");
//return userRepository.findTop2ByPhoneStartingWithAndAddressContaining(phone, address, new Sort(order)); //List<Order> orders = new ArrayList<Order>();
//orders.add(new Order(Direction.DESC,"name"));
//orders.add(new Order(Direction.ASC,"phone"));
//return userRepository.findTop2ByPhoneStartingWithAndAddressContaining(phone, address, new Sort(orders); } }
Client.java(测试类)
package com.zang.usermanage.test; import java.util.List; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page; import com.zang.usermanage.exception.UserNotFound;
import com.zang.usermanage.model.User;
import com.zang.usermanage.service.UserService; public class Client { public static void printUser(User user){
StringBuilder sb = new StringBuilder();
sb.append("id="+user.getId());
sb.append("name="+user.getName());
sb.append("address="+user.getAddress());
sb.append("phone="+user.getPhone());
System.out.println(sb.toString()); } /**
* 打印分页信息
* @param pageInfo
*/
public static <T> void printPageInfo(Page<T> pageInfo){
StringBuilder sb = new StringBuilder();
sb.append("当前是第几页="+pageInfo.getNumber()).append("\n");
sb.append("当前页查得的记录数="+pageInfo.getNumberOfElements()).append("\n");
sb.append("每页需要查询的条数="+pageInfo.getSize()).append("\n");
sb.append("总共符合条件的记录数="+pageInfo.getTotalElements()).append("\n");
sb.append("总共的页数是="+pageInfo.getTotalPages()).append("\n");
System.out.println(sb.toString());
} /**
* 不分页查询
* @param userService
*/
public static void testListByConditonNoPage(UserService userService){ List<User> users = userService.getUsersByConditionNoPage("136","路"); if (users!=null){
for (int i=0; i<users.size();i++){
printUser(users.get(i));
}
}
} /**
* 分页查询
* @param userService
*/
public static void testListByConditonWithPage(UserService userService){ //传入条件和分页信息
Page<User> userPage = userService.getUsersByConditionWithPage("136","路",0,2);
//打印分页信息
printPageInfo(userPage); List<User> users = userPage.getContent(); if (users!=null){
for (int i=0; i<users.size();i++){
printUser(users.get(i));
}
}
} public static void main(String[] arg) throws UserNotFound{ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) ac.getBean("userService"); //testListByConditonNoPage(userService);
testListByConditonWithPage(userService);
}
}
效果:
Spring Data JPA入门的更多相关文章
- spring data jpa入门学习
本文主要介绍下spring data jpa,主要聊聊为何要使用它进行开发以及它的基本使用.本文主要是入门介绍,并在最后会留下完整的demo供读者进行下载,从而了解并且开始使用spring data ...
- Spring Data Jpa 入门学习
本文主要讲解 springData Jpa 入门相关知识, 了解JPA规范与Jpa的实现,搭建springboot+dpringdata jpa环境实现基础增删改操作,适合新手学习,老鸟绕道~ 1. ...
- Spring Data JPA入门及深入
一:Spring Data JPA简介 Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问 ...
- Spring Data JPA 入门Demo
什么是JPA呢? 其实JPA可以说是一种规范,是java5.0之后提出来的用于持久化的一套规范:它不是任何一种ORM框架,在我看来,是现有ORM框架在这个规范下去实现持久层. 它的出现是为了简化现有的 ...
- Spring Data JPA 入门篇
Spring Data JPA是什么 它是Spring基于ORM框架(如hibernate,Mybatis等).JPA规范(Java Persistence API)封装的一套 JPA应用框架,可使开 ...
- Spring Data Jpa --- 入门
一.概述 Spring Data是Spring下的一个子项目,用于简化数据库访问,并支持云服务的开源框架.Spring Data支持NoSQL和 关系数据存储,其主要目标是使得数据库的访问变得方便快捷 ...
- 【ORM框架】Spring Data JPA(一)-- 入门
本文参考:spring Data JPA入门 [原创]纯干货,Spring-data-jpa详解,全方位介绍 Spring Data JPA系列教程--入门 一.Spring Data JPA介 ...
- 深入浅出学Spring Data JPA
第一章:Spring Data JPA入门 Spring Data是什么 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map ...
- Spring Data JPA 教程(翻译)
写那些数据挖掘之类的博文 写的比较累了,现在翻译一下关于spring data jpa的文章,觉得轻松多了. 翻译正文: 你有木有注意到,使用Java持久化的API的数据访问代码包含了很多不必要的模式 ...
随机推荐
- vuetify | vue | 文件上传组件 | file | upload | form input[type="file"]
今天无聊地写vuecli3听歌的时候,遇到了上传文件到Django的自我需求,然后就到vuetify的表单组件里找upload btn,发现居然没有!!! 顿时惊了个呆,要知道之前用element做操 ...
- 剑指Offer_编程题_21
题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数. class Solution { public: void push(int value) { st.push(val ...
- 【Sql Server】SQL SERVER 递归查询
SQL SERVER 2005之前的版本只能用函数方法实现,SQL SERVER 2005之后新增了CTE功能,可以利用CTE实现递归查询: CTE:公用表达式Common Table Express ...
- Sobel 边缘检测算子
转自:http://blog.csdn.net/xiaqunfeng123/article/details/17302003 Sobel 算子是一个离散微分算子 (discrete different ...
- TensorFlow资源整理
什么是TensorFlow? TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库.节点(Nodes)在图中表示数学操作,图中的线(edges)则表示 ...
- Kaldi nnet3的fastlstm与标准LSTM
标准LSTM: 与标准LSTM相比,Kaldi的fastlstm对相同或类似的矩阵运算进行了合并. # Component specific to 'projected ...
- adb devices 报错处理
手机连接pc,cmd窗口输入命令adb devices报如下错误: adb server version (31) doesn't match this client (40)然后adb停止运行 这是 ...
- LeetCode第十二题-将数字转化为罗马数字
Integer to Roman 问题简介:将输入的int类型数字转化为罗马数字 问题详解:罗马数字由七个不同的符号表示:I,V,X,L,C,D和M 符号-数值 I - 1 V - 5 X -10 L ...
- 微信小程序-制作简易豆瓣笔记
demo截图: 图书: 电影: 共工欲善其事,必先利其器: 小程序编辑器下载地址 : https://mp.weixin.qq.com/debug/wxadoc/dev/dev ...
- IEnumerable<T>和IQueryable<T>区别
LINQ查询方法一共提供了两种扩展方法,在System.Linq命名空间下,有两个静态类:Enumerable类,它针对继承了IEnumerable<T>接口的集合进行扩展:Queryab ...