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