欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Data Jpa的详细介绍

程序员文章站 2022-04-21 16:30:48
...

Spring Data Jpa的详细介绍

一、Jpa是什么

JPA(Java Persistence API)
意即Java持久化API,是Sun官方在JDK5.0后提出的Java持久化规范,JPA的出现主要是为了简化持久层开发以及整合ORM技术,结束Hibernate、TopLink、JDO等ORM框架各自为营的局面。JPA是在吸收现有ORM框架的基础上发展而来,易于使用,伸缩性强。
总的来说,JPA包括以下3方面的技术:
ORM映射:支持XML和注解描述对象和表之间的映射关系
API:操作实体对象来执行CRUD(create read update delete)(增删改查)操作
查询语言:通过面向对象而非面向数据库的查询语言(JPQL)查询数据

二、Spring Data Jpa 简介

Spring Data JPA 是 Spring 基于 ORM 框架JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。Spring Data JPA不需要过多的关心Dao层的实现,只需关注我们继承的接口,按照一定的规则去编写我们的接口即可,spring会按照规范动态生成我们接口的实现类进行注入,并且实现类里包含了一些常规操作的方法实现。如果使用JPA提供的接口来操作ORM框架,可以不写任何实现就能对数据库进行CRUD操作,还可以进行简单的分页,排序操作。

三、Spring Data Jpa核心接口(API)

Repository:
所有接口的父接口,而且是一个空接口,目的是为了统一所有Repository的类型,让组件扫描的时候能进行识别。

CrudRepository:
是Repository的子接口,提供CRUD(增删改查)的功能。

PagingAndSortingRepository
是CrudRepository的子接口,添加分页和排序的功能。

JpaRepository
是PagingAndSortingRepository的子接口,增加了一些实用的功能,例如批量操作。

JpaSpecificationExecutor:用来做负责动态条件查询的接口。

Specification:是Spring Data JPA提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可。

四、Spring Data Jpa的使用

**1.在项目的pom.xml中添加spring-data-jpa的依赖配置

<!-- c3p0数据库连接池 -->
	<dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>${c3p0.version}</version>
    </dependency>

	<!-- spring-data-jpa -->
	<dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.9.0.RELEASE</version>
    </dependency>

2.在spring核心配置文件中配置spring-data-jpa相关项

applicationContext.xml
与hibernate Mybatis配置一样


<?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:jdbc="http://www.springframework.org/schema/jdbc" 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/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.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">

	<!-- 1、创建数据源 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUrl"
			value="jdbc:mysql://localhost:3306/1905a?useUnicode=true&amp;characterEncoding=UTF-8" />
		<property name="user" value="root" />
		<property name="password" value="root" />
	</bean>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<!-- 数据源 -->
		<property name="dataSource" ref="dataSource" />
		<!-- 扫描实体类的包 -->
		<property name="packagesToScan" value="com.fh.model" />
		<!-- 指定jpa的提供商 -->
		<property name="persistenceProvider">
			<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
		</property>
		<!--JPA的供应商适配器 -->
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<!-- true: HBM2DDL_AUTO为"update" ,有表就维护表,没有表就创建表 false: 默认为false -->
				<property name="generateDdl" value="true" />
				<property name="database" value="MYSQL" />
				<!-- 数据库方言:根据这个方言生成不同数据库的sql -->
				<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
				<property name="showSql" value="true" />
			</bean>
		</property>
		<!-- 可选:Jpa的方言 -->
		<property name="jpaDialect">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
		</property>
	</bean>

	<!-- 3、配置事务 -->
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	<!-- 事务通知和aop切面这里就不配置: 今天是dao层的代码 -->

	<!-- 4、 配置SpringDataJpa的相关配置 base-package:指定基包 entity-manager-factory-ref: 
		引用实体类管理器工厂 transaction-manager-ref: 引用平台事务管理器 -->
	<jpa:repositories base-package="com.fh.dao"
		entity-manager-factory-ref="entityManagerFactory"
		transaction-manager-ref="transactionManager" />

	<!-- 5、开启组件的扫描 -->
	<context:component-scan base-package="com.fh" />

	<!-- 定义advice,配置传播特性、事务隔离级别、只读事务、回滚策略 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
			<tx:method name="update*" propagation="REQUIRED"
				rollback-for="java.lang.Exception" />
			<tx:method name="delete*" propagation="REQUIRED"
				rollback-for="java.lang.Exception" />
			<tx:method name="save*" propagation="REQUIRED"
				rollback-for="java.lang.Exception" />
			<tx:method name="*" propagation="REQUIRED" read-only="true" />
		</tx:attributes>
	</tx:advice>

	<!-- 切点配置 execution(* com.fh.service.impl.*.*(..)) 第一个*:任意返回值 第二个*:包下任意的类 
		第三个*:类中的所有方法 (..):任意参数 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.fh.service.impl.*.*(..))"
			id="servicePointcut" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut" />
	</aop:config>

</beans> 

3.编写实体类并使用JPA注解配置实体类和数据库表的映射关系
JPA不需要自己创建数据库,只需要在实体类中通过注解配置好,就会自动创建出所需要的数据
注意:日期这块要特别注意

User.class

//name="t_user" 数据库的表名
@Table(name="t_user")
//@Entity表明是一个实体类
@Entity
public class User {

	@Id
	//指名这是一个主键,auto会自动根据方言来生成主键,IDENTITY mysql的主键生成
	@GeneratedValue(strategy = GenerationType.AUTO)
	//@Column 字段名,类型会自动根据属性类型匹配,如果不写,默认就是属性名
	@Column(name="user_id")
	private Integer userId;
	
	//定义字段名
	@Column(name="user_name")
	private String userName;
	
	@Column(name="real_name")
	private String realName;//真实姓名
	
	@Column(name="user_sex")
	private Integer userSex;//性别
	
    //@DateTimeFormat是日期的展示格式
	//加上后,格式为:2020-01-01
	//不加:   默认格式为:2020-01-01 12:03:22
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	//@Temporal设置数据库的字段类型  ,
	///加上为:date类型(2020-01-01) 
	//不加默认:datetime(2020-01-01 12:03:22)
	//与@DateTimeFormat一定要对应好
	@Temporal(TemporalType.DATE)
	@Column(name="user_birthday")
	//json数据的展示
	@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
	private Date userBirthday;//生日
	
	//创建日期有时分秒
	//不能省略
	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	@Column(name="create_date")
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
	private Date  createDate;//创建时间 
	 
	//不能省略
	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	@Column(name="update_Date")
	@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
	private Date  updateDate;//修改时间


//生成getter setter方法
}

建立包结构

service serviceImpl
Repository 替代了dao层

通过JPA进行增删改查

这里通过junit进行测试,所以需要导入相关的jar包

 <!-- java单元测试框架 -->
		   <dependency>
			    <groupId>junit</groupId>
			    <artifactId>junit</artifactId>
			    <version>4.12</version>
			</dependency>

Repository.java

 /**
 * Repository替代了dao类
 * 需要继承extends JpaRepository<User, Integer>  Integer 是id的类型
 * 只要继承该类,就会自动有增删改查 的方法,直接可以调用
 * @author srj
 *
 *继承JpaRepository(增删改查),
 *第一个泛型:我们要操作的实体类,
 *第二个泛型:主键属性的数据类型
 */
public interface UserRepository extends JpaRepository<User, Integer>{

	//只要继承JpaRepository,默认会有增删改查的方法,直接调用就可以

}

测试类
UserRepositoryTest.java

//用于指定junit运行环境,是junit提供给其他框架测试环境接口扩展,为了便于使用spring的依赖注入
//spring提供了org.springframework.test.context.junit4.SpringJUnit4ClassRunner作为Junit测试环境
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class UserRepositoryTest {
	
	@Autowired
	private UserRepository userRepository;
	
}

准备完成:

增加:

UserRepositoryTest.java

	/**
	 * 新增
	 */
	@Test
	public void addUser() {
		User user = new User();
		user.setUserName("李四111");
		user.setUserSex(2);
		user.setUserBirthday(new Date());
		//直接调用新增方法即可
		userRepository.saveAndFlush(user);
	}

删除

/**
 * 删除
 */
@Test
public void deleteUser() {
//直接调用即可
	userRepository.delete(2);
}

修改

	/**
	 * 修改
	 */
	@Test
	public void updateUser() {
		User user = userRepository.findOne(1);
		user.setUserName("小红");
		user.setUserEmail("[email protected]");
		user.setCreateDate(new Date());
		userRepository.saveAndFlush(user);
		
	}

查询

/**
	 * 查询
	 */
	@Test
	public void queryUser() {
		List<User> userList = userRepository.findAll();
		//循环输出所有值
		for (Iterator iterator = userList.iterator(); iterator.hasNext();) {
			User user = (User) iterator.next();
			System.out.println(user.getUserName());
		}
	}

如果要进行特殊查询等,需要继承接口JpaSpecificationExecutor,根据规则自定方法
//继承JpaSpecificationExecutor(复杂查询,动态查询),泛型: 就是我们操作的实体类

五、Spring Data Jpa查询方法命名规则

Spring Data JPA为自定义查询提供了一些表达条件查询的关键字,大致如下:
And:等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd);

Or :等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr);

Between :等价于 SQL 中的 between 关键字,比如 findBySalaryBetween(int max, int min);

LessThan:等价于 SQL 中的 “<”,比如 findBySalaryLessThan(int max);

GreaterThan:等价于 SQL 中的">",比如 findBySalaryGreaterThan(int min);

IsNull :等价于 SQL 中的 “is null”,比如 findByUsernameIsNull();

IsNotNull:等价于 SQL 中的 “is not null”,比如 findByUsernameIsNotNull();

NotNull:与 IsNotNull 等价;

Like :等价于 SQL 中的 “like”,比如 findByUsernameLike(String user);

NotLike :等价于 SQL 中的 “not like”,比如 findByUsernameNotLike(String user);

OrderBy:等价于 SQL 中的 “order by”,比如 findByUsernameOrderBySalaryAsc(String user);

Not:等价于 SQL 中的 “!=”,比如 findByUsernameNot(String user);

In :等价于 SQL 中的 “in”,比如 findByUsernameIn(Collection userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;

NotIn:等价于 SQL 中的 “not in”,比如 findByUsernameNotIn(Collection userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;

public interface UserDao extends JpaRepository<User, Integer>,JpaSpecificationExecutor<User>{
	
}

And使用

//and
	User findByUserNameAndUserSex(String userName,Integer userSex);
/**
	 * 通过userName和userSex查询
	 */
	@Test
	public void findByUsernameAndUserSexTest() {
		User user = userRepository.findByUserNameAndUserSex("李四", 10);
		System.out.println(user);
	}

between使用

//between
	List<User> findByUserSexBetween(int maxSex, int minSex);
   /**
	 * between
	 */
	@Test
	public void findByUserSexBetweenTest() {
		List<User> userlist = userRepository.findByUserSexBetween(0, 4);
		//循环输出所有值
		for (Iterator iterator = userlist.iterator(); iterator.hasNext();) {
			User user = (User) iterator.next();
			System.out.println(user.getUserName());
		}
	}

like使用

//like
	List<User> findByUserNameLike(String user);
/**
	 * like
	 */
	@Test
	public void findByUserNameLikeTest() {
		//查询姓李的人
		List<User> userlist = userRepository.findByUserNameLike("李%");
		
		//循环输出所有值
		for (Iterator iterator = userlist.iterator(); iterator.hasNext();) {
			User user = (User) iterator.next();
			System.out.println(user.getUserName());
		}
	}
	

OrderBy使用

//OrderBy:等价于 SQL 中的 "order by",比如 
	List<User> findByUserNameLikeOrderByUserIdAsc(String user);
/**
	 * 条件查询+排序
	 */
	@Test
	public void findByUserNameOrderByUserSexAscTest() {
		//查询姓李的人
		//List<User> userlist = userRepository.findByUserNameOrderByUserIdAsc("");
		List<User> userlist = userRepository.findByUserNameLikeOrderByUserIdAsc("李%");
		//循环输出所有值
		for (Iterator iterator = userlist.iterator(); iterator.hasNext();) {
			User user = (User) iterator.next();
			System.out.println("name======"+user.getUserName()+"======sex=====");
		}
	}
	

JPA分页使用

一.分页

UserService .java

public interface UserService {

	//分页
	public List<User> queryPage(Integer pageIndex,Integer pagesize);

}

UserServiceImpl .java

@Service
public class UserServiceImpl implements UserService{

	@Autowired
	private UserRepository userRepository;
	
	/**
	 * 分页
	 */
	public List<User> queryPage(Integer pageIndex,Integer pagesize){
		//构造分页对象
		PageRequest pageRequest = new PageRequest(pageIndex, pagesize);
		
		//开始分页查询获取page对象
		Page<User> page = userRepository.findAll(pageRequest);
		//查询
		List<User> userList = page.getContent();
		
		return userList;
	}
}

UserServiceImplTest.java

//用于指定junit运行环境,是junit提供给其他框架测试环境接口扩展,为了便于使用spring的依赖注入
//spring提供了org.springframework.test.context.junit4.SpringJUnit4ClassRunner作为Junit测试环境
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class UserServiceImplTest {
	
	@Autowired
	private UserService userService;
	
	/**
	 * 测试分页
	 */
	@Test
	public void queryPageTest() {
		List<User> userList = userService.queryPage(0,2);
		for (User user : userList) {
			System.out.println(user);
			System.out.println(user.getUserName());
		}
	}

}

二.分页+排序 先排序再分页

UserService .java

//分页+排序
	public List<User> queryPageAndSorting(Integer pageIndex,Integer pagesize,String name,Direction orderBy);

UserServiceImpl .java

/**
 * 先排序再分页
 * 分页+排序
 * @param pageIndex 当前第几页 从0开始
 * @param pagesize 每页条数
 * @param name 按照什么属性【字段名】分页
 * @param orderBy 排序规则:asc desc
 * @return
 */
public List<User> queryPageAndSorting(Integer pageIndex,Integer pagesize,String name,Direction orderBy){
	//排序
	Sort sort = new Sort(orderBy,name);
	//构建分页对象
	PageRequest pageRequest = new PageRequest(pageIndex, pagesize,sort);
	//开始分页查询,获取page对象
	Page<User> page = userRepository.findAll(pageRequest);
	//获取分页的list集合
	List<User> userList = page.getContent();
	return userList;
	
}

UserServiceImplTest.java

/**
 * 测试分页+排序
 */
@Test
public void queryPageAndSortingTest() {
	List<User> userList = userService.queryPageAndSorting(0,2,"userId",Direction.DESC);
	for (User user : userList) {
		System.out.println(user);
	}
}

三.先分页再排序

UserService .java

//分页+排序
		public List<User> querySortingAndPage(Integer pageIndex,Integer pagesize,String name,Direction orderBy);

UserServiceImpl .java

/**
	 * 先分页再排序
	 * @param pageIndex
	 * @param pagesize
	 * @param name
	 * @param orderBy
	 * @return
	 */
	public List<User> querySortingAndPage(Integer pageIndex,Integer pagesize,String name,Direction orderBy){
		PageRequest pageRequest = new PageRequest(pageIndex, pagesize);
		//开始分页查询,获取page对象
		Page<User> page = userRepository.findAll(pageRequest);
		Sort sort = new Sort(orderBy,name);
		//Sort sort2 = page.getSort();
		//获取分页的list集合
		List<User> userList = page.getContent();
		//排序
		PageRequest pageRequest1 = new PageRequest(pageIndex, pagesize,sort);
		//开始分页查询,获取page对象
		Page<User> page1 = userRepository.findAll(pageRequest);
		//获取分页的list集合
		List<User> userList1 = page.getContent();
		return userList1;
	}

UserServiceImplTest.java

@Test
	public void querySortingAndPage() {
		List<User> userList = userService.querySortingAndPage(0,2,"userId",Direction.DESC);
		for (User user : userList) {
			System.out.println(user);
		}
	}
相关标签: jpa mysql