Spring Data Jpa的详细介绍

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);
		}
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章