學習Spring Data JPA

簡介

Spring Data 是spring的一個子項目,在官網上是這樣解釋的:

Spring Data 是為數據訪問提供一種熟悉且一致的基于Spring的編程模型,同時仍然保留底層數據存儲的特??殊特性。它可以輕松使用數據訪問技術,可以訪問關系和非關系數據庫。

簡而言之就是讓訪問數據庫能夠更加便捷。

Spring Data 又包含多個子項目:

  • Spring Data JPA

  • Spring Data Mongo DB

  • Spring Data Redis

  • Spring Data Solr

本文章主要介紹Spring Data JPA的相關知識:

傳統方式訪問數據庫

使用原始JDBC方式進行數據庫操作

創建數據表:

917807-20170522091554898-1468234684.png

917807-20170522091604351-450682169.png

開發JDBCUtil工具類

獲取Connection,釋放資源,配置的屬性放在配置文件中,通過代碼的方式將配置文件中的數據加載進來。

package com.zzh.util;import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class JDBCUtil {public static Connection getConnection() throws Exception {InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");Properties properties = new Properties();properties.load(inputStream);String url = properties.getProperty("jdbc.url");String user = properties.getProperty("jdbc.user");String password = properties.getProperty("jdbc.password");String driverClass = properties.getProperty("jdbc.driverClass");Class.forName(driverClass);Connection connection = DriverManager.getConnection(url, user, password);return connection;}public static void release(ResultSet resultSet, Statement statement,Connection connection) {if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}

建立對象模型和DAO

917807-20170522155703195-1084405773.png

package com.zzh.dao;import com.zzh.domain.Student;
import com.zzh.util.JDBCUtil;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;/*** Created by zhao on 2017/5/22.*/
public class StudentDAOImpl implements StudentDAO{/*** 查詢學生*/@Overridepublic List<Student> query() {List<Student> students = new ArrayList<>();Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;String sql = "select * from student";try {connection = JDBCUtil.getConnection();preparedStatement = connection.prepareStatement(sql);resultSet = preparedStatement.executeQuery();Student student = null;while (resultSet.next()) {int id = resultSet.getInt("id");String name = resultSet.getString("name");int age = resultSet.getInt("age");student = new Student();student.setId(id);student.setAge(age);student.setName(name);students.add(student);}} catch (Exception e) {e.printStackTrace();}finally {JDBCUtil.release(resultSet,preparedStatement,connection);}return students;}/*** 添加學生*/@Overridepublic void save(Student student) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;String sql = "insert into student(name,age) values (?,?)";try {connection = JDBCUtil.getConnection();preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1, student.getName());preparedStatement.setInt(2,student.getAge());preparedStatement.executeUpdate();} catch (Exception e) {e.printStackTrace();}finally {JDBCUtil.release(resultSet,preparedStatement,connection);}}
}

可以看到基于原始的jdbc的編程,同一個dao方法中有太多的重復代碼。


使用Spring JdbcTemplate進行數據庫操作

Spring內置模板JdbcTemplate的出現大大提高了開發效率。

  • 創建spring配置文件:
<?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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"><context:property-placeholder location="classpath:db.properties"/><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driverClass}"/><property name="username" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/><property name="url" value="${jdbc.url}"/></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/></bean><bean id="studentDAO" class="com.zzh.dao.StudentDAOSpringJdbcImpl"><property name="jdbcTemplate" ref="jdbcTemplate"/></bean>
</beans>
  • 編寫查詢學生和保存學生方法
package com.zzh.dao;import com.zzh.domain.Student;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;public class StudentDAOSpringJdbcImpl implements StudentDAO{private JdbcTemplate jdbcTemplate;public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic List<Student> query() {final List<Student> students = new ArrayList<>();String sql = "select * from student";jdbcTemplate.query(sql, new RowCallbackHandler() {@Overridepublic void processRow(ResultSet resultSet) throws SQLException {int id = resultSet.getInt("id");String name = resultSet.getString("name");int age = resultSet.getInt("age");Student student = new Student();student.setId(id);student.setAge(age);student.setName(name);students.add(student);}});return students;}@Overridepublic void save(Student student) {String sql = "insert into student(name,age) values (?,?)";jdbcTemplate.update(sql, new Object[]{student.getName(), student.getAge()});}
}

弊端分析

  • DAO中有太多的代碼

  • DAOImpl有大量重復的代碼

  • 開發分頁或者其他的功能還要重新封裝


Spring Data

用上面的兩種方式進行數據庫操作可以感受到代碼的重復性和易用性都是有缺點的,現在先以一個小例子進行spring data操作數據庫的基本示范,之后再逐步分析他的具體功能。

小例子

添加pom依賴:

<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-jpa</artifactId><version>1.8.0.RELEASE</version>
</dependency>
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>4.3.6.Final</version>
</dependency>
  • 創建一個新的spring配置文件:beans-new.xml:
<?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:context="http://www.springframework.org/schema/context"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.xsdhttp://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"><context:property-placeholder location="classpath:db.properties"/><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driverClass}"/><property name="username" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/><property name="url" value="${jdbc.url}"/></bean><!-- 配置EntityManagerFactory--><bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><property name="dataSource" ref="dataSource"/><property name="jpaVendorAdapter"><bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/></property><property name="packagesToScan" value="com.zzh"/><property name="jpaProperties"><props><prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop><prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop><prop key="hibernate.show_sql">true</prop><prop key="hibernate.format_sql">true</prop><prop key="hibernate.hbm2ddl.auto">update</prop></props></property></bean><!--事務管理器--><bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="entityManagerFactory" ref="entityManagerFactory"/></bean><!--支持注解的事物--><tx:annotation-driven transaction-manager="transactionManager"/><!--spring data--><jpa:repositories base-package="com.zzh" entity-manager-factory-ref="entityManagerFactory"/><context:component-scan base-package="com.zzh"/>
</beans>

LocalContainerEntityManagerFactoryBean:

適用于所有環境的FactoryBean,能全面控制EntityManagerFactory配置,非常適合那種需要細粒度定制的環境。

jpaVendorAdapter:

用于設置JPA實現廠商的特定屬性,如設置hibernate的是否自動生成DDL的屬性generateDdl,這些屬性是廠商特定的。目前spring提供HibernateJpaVendorAdapter,OpenJpaVendorAdapter,EclipseJpaVendorAdapter,TopLinkJpaVenderAdapter四個實現。

jpaProperties:

指定JPA屬性;如Hibernate中指定是否顯示SQL的“hibernate.show_sql”屬性.

  • 建立實體類Employee:

917807-20170522201411335-1344436573.png

  • 自定義接口并繼承Repository接口

繼承的Repository接口泛型里的第一個參數是要操作的對象,即Employee;第二個參數是主鍵id的類型,即Integer。
方法即為根據名字找員工,這個接口是不用寫實現類的。為什么可以只繼承接口定義了方法就行了呢,因為spring data底層會根據一些規則來進行相應的操作。
所以方法的名字是不能隨便寫的,不然就無法執行想要的操作。

package com.zzh.repository;import com.zzh.domain.Employee;
import org.springframework.data.repository.Repository;public interface EmployeeRepository extends Repository<Employee,Integer>{Employee findByName(String name);
}
  • 創建測試類

findByName方法體中先不用寫,直接執行空的測試方法,我們的Employee表就自動被創建了,此時表中沒有數據,向里面添加一條數據用于測試:

917807-20170522215047804-355275733.png

package com.zzh.repository;import com.zzh.domain.Employee;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class EmployeeRepositoryTest {private ApplicationContext ctx = null;private EmployeeRepository employeeRepository = null;@Beforepublic void setUp() throws Exception {ctx = new ClassPathXmlApplicationContext("beans-new.xml");employeeRepository = ctx.getBean(EmployeeRepository.class);}@Afterpublic void tearDown() throws Exception {ctx = null;}@Testpublic void findByName() throws Exception {Employee employee = employeeRepository.findByName("zhangsan");System.out.println("id:" + employee.getId() + " name:" + employee.getName() + " age:" + employee.getAge());}}

再執行測試類方法體中的內容:

917807-20170522215237882-678178166.png


Repository接口

  1. Repository接口是Spring Data的核心接口,不提供任何方法

  2. 使用 @ RepositoryDefinition注解跟繼承Repository是同樣的效果,例如 @ RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class)

  3. Repository接口定義為:public interface Repository<T, ID extends Serializable> {},Repository是一個空接口,標記接口;只要將自定義的接口繼承Repository,就會被spring來管理。

Repository的子接口

917807-20170522223916132-1665772406.png

  • CrudRepository :繼承 Repository,實現了CRUD相關的方法。

  • PagingAndSortingRepository : 繼承 CrudRepository,實現了分頁排序相關的方法。

  • JpaRepository :繼承 PagingAndSortingRepository ,實現了JPA規范相關的方法。

917807-20170522223904679-681095022.png

Repository中查詢方法定義規則

上面一個例子中使用了findByName作為方法名進行指定查詢,但是如果把名字改為其他沒有規則的比如test就無法獲得正確的查詢結果。

有如下規則:

917807-20170523091308398-1247277875.png

917807-20170523091651663-106020302.png

最右邊是sql語法,中間的就是spring data操作規范,現在寫一些小例子來示范一下:

先在employee表中初始化了一些數據:
917807-20170523092341148-870427246.png

在繼承了Repository接口的EmployeeRepository接口中新增一個方法:

917807-20170523093450679-2080962887.png

條件是名字以test開頭,并且年齡小于22歲,在測試類中進行測試:

917807-20170523093618054-1340669783.png

得到結果:

917807-20170523093746242-2037251949.png

在換一個名字要在某個范圍以內并且年齡要小于某個值:

917807-20170523101310663-801837867.png

測試類:

917807-20170523101340742-1274203366.png

得到結果,只有test1和test2,因為在test1,test2和test3里面,年齡還要小于22,所以test3被排除了:
917807-20170523101359585-1970300071.png

弊端分析

對于按照方法名命名規則來使用的弊端在于:

  • 方法名會比較長

  • 對于一些復雜的查詢很難實現


Query注解

  • 只需要將 @ Query標記在繼承了Repository的自定義接口的方法上,就不再需要遵循查詢方法命名規則。

  • 支持命名參數及索引參數的使用

  • 本地查詢

案例使用:

  • 查詢Id最大的員工信息:
 @Query("select o from Employee o where id=(select max(id) from Employee t1)")Employee getEmployeeById();

注意:Query語句中第一個Employee是類名

測試類:

@Testpublic void getEmployeeByMaxId() throws Exception {Employee employee = employeeRepository.getEmployeeByMaxId();System.out.println("id:" + employee.getId() + " name:" + employee.getName() + " age:" + employee.getAge());}
  • 根據占位符進行查詢

注意占位符后從1開始

    @Query("select o from Employee o where o.name=?1 and o.age=?2")List<Employee> queryParams1(String name, Integer age);

測試方法:

@Testpublic void queryParams1() throws Exception {List<Employee> employees = employeeRepository.queryParams1("zhangsan", 20);for (Employee employee : employees) {System.out.println("id:" + employee.getId() + " name:" + employee.getName() + " age:" + employee.getAge());}}
  • 根據命名參數的方式
   @Query("select o from Employee o where o.name=:name and o.age=:age")List<Employee> queryParams2(@Param("name") String name, @Param("age") Integer age);
  • like查詢語句
@Query("select o from Employee o where o.name like %?1%")List<Employee> queryLike1(String name);
@Testpublic void queryLike1() throws Exception {List<Employee> employees = employeeRepository.queryLike1("test");for (Employee employee : employees) {System.out.println("id:" + employee.getId() + " name:" + employee.getName() + " age:" + employee.getAge());}}

查詢包含test的記錄:

917807-20170523141713226-1077587238.png

P.s 這里查詢也得到了結果,不過我的idea卻在sql語句里面提示有錯,我懷疑是我的idea版本的問題,我的是2017.1.3版本的:
917807-20170523142928445-1388456758.png

  • like語句使用命名參數
    @Query("select o from Employee o where o.name like %:name%")List<Employee> queryLike2(@Param("name") String name);

本地查詢

所謂本地查詢,就是使用原生的sql語句進行查詢數據庫的操作。但是在Query中原生態查詢默認是關閉的,需要手動設置為true:

    @Query(nativeQuery = true, value = "select count(1) from employee")long getCount();

方法是拿到記錄數,這里使用的employee是表而不是類,也是原生態查詢的特點。


更新操作整合事物使用

  • 在dao中定義方法根據id來更新年齡(Modifying注解代表允許修改)
    @Modifying@Query("update Employee o set o.age = :age where o.id = :id")void update(@Param("id") Integer id, @Param("age") Integer age);

要注意,執行更新或者刪除操作是需要事物支持,所以通過service層來增加事物功能,在update方法上添加Transactional注解。

package com.zzh.service;import com.zzh.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class EmployeeService {@Autowiredprivate EmployeeRepository employeeRepository;@Transactionalpublic void update(Integer id, Integer age) {employeeRepository.update(id,age);}
}
  • 刪除操作

刪除操作同樣需要Query注解,Modifying注解和Transactional注解

    @Modifying@Query("delete from Employee o where o.id = :id")void delete(@Param("id") Integer id);
    @Transactionalpublic void delete(Integer id) {employeeRepository.delete(id);}

CrudRepository接口

917807-20170523184038085-29589914.png

  • 創建接口繼承CrudRepository
package com.zzh.repository;import com.zzh.domain.Employee;
import org.springframework.data.repository.CrudRepository;public interface EmployeeCrudRepository extends CrudRepository<Employee,Integer>{}
  • 在service層中調用
    @Autowiredprivate EmployeeCrudRepository employeeCrudRepository;

存入多個對象:

    @Transactionalpublic void save(List<Employee> employees) {employeeCrudRepository.save(employees);}

創建測試類,將要插入的100條記錄放在List中:

package com.zzh.repository;import com.zzh.domain.Employee;
import com.zzh.service.EmployeeService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.ArrayList;
import java.util.List;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:beans-new.xml"})
public class EmployeeCrudRepositoryTest {@Autowiredprivate EmployeeService employeeService;@Testpublic void testSave() {List<Employee> employees = new ArrayList<>();Employee employee = null;for (int i = 0; i < 100; i++) {employee = new Employee();employee.setName("test" + i);employee.setAge(100 - i);employees.add(employee);}employeeService.save(employees);}
}

為了不影響之前的employee表,現在在Employee類上面加上Table注解,指定一個新的表名,之前沒有加這個注解默認使用了類名當作表名,也就是employee,現在指定新表test_employee。

917807-20170523192717648-1556336500.png

執行測試類中的方法,控制臺輸出了很多插入語句,打開數據庫查看,新表創建成功,同時插入了100條數據:

917807-20170523193040101-1128212660.png

CrudRepository總結

可以發現在自定義的EmployeeCrudRepository中,只需要聲明接口并繼承CrudRepository就可以直接使用了。


PagingAndSortingRepository接口

  • 該接口包含分頁和排序的功能

  • 帶排序的查詢:findAll(Sort sort)

  • 帶排序的分頁查詢:findAll(Pageable pageable)

自定義接口

package com.zzh.repository;import com.zzh.domain.Employee;
import org.springframework.data.repository.PagingAndSortingRepository;public interface EmployeePagingAndSortingRepository extends PagingAndSortingRepository<Employee, Integer> {}

測試類

分頁:

package com.zzh.repository;import com.zzh.domain.Employee;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:beans-new.xml"})
public class EmployeePagingAndSortingRepositoryTest {@Autowiredprivate EmployeePagingAndSortingRepository employeePagingAndSortingRepository;@Testpublic void testPage() {//第0頁,每頁5條記錄Pageable pageable = new PageRequest(0, 5);Page<Employee> page = employeePagingAndSortingRepository.findAll(pageable);System.out.println("查詢的總頁數:"+ page.getTotalPages());System.out.println("總記錄數:"+ page.getTotalElements());System.out.println("當前第幾頁:"+ page.getNumber()+1);System.out.println("當前頁面對象的集合:"+ page.getContent());System.out.println("當前頁面的記錄數:"+ page.getNumberOfElements());}}

917807-20170523202810117-1486459772.png

排序:

在PageRequest的構造函數里還可以傳入一個參數Sort,而Sort的構造函數可以傳入一個Order,Order可以理解為關系型數據庫中的Order;Order的構造函數Direction和property參數代表按照哪個字段進行升序還是降序。

現在按照id進行降序排序:

 @Testpublic void testPageAndSort() {Sort.Order order = new Sort.Order(Sort.Direction.DESC, "id");Sort sort = new Sort(order);Pageable pageable = new PageRequest(0, 5, sort);Page<Employee> page = employeePagingAndSortingRepository.findAll(pageable);System.out.println("查詢的總頁數:"+ page.getTotalPages());System.out.println("總記錄數:"+ page.getTotalElements());System.out.println("當前第幾頁:" + page.getNumber() + 1);System.out.println("當前頁面對象的集合:"+ page.getContent());System.out.println("當前頁面的記錄數:"+ page.getNumberOfElements());}

917807-20170523205334070-1528758030.png

可以看到id是從100開始降序排列。


JpaRepository接口

917807-20170524080543013-851438576.png

  • 創建接口繼承JpaRepository
package com.zzh.repository;import com.zzh.domain.Employee;
import org.springframework.data.jpa.repository.JpaRepository;public interface EmployeeJpaRepository extends JpaRepository<Employee,Integer>{
}
  • 測試類

按id查找員工

package com.zzh.repository;import com.zzh.domain.Employee;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:beans-new.xml"})
public class EmployeeJpaRepositoryTest {@Autowiredprivate EmployeeJpaRepository employeeJpaRepository;@Testpublic void testFind() {Employee employee = employeeJpaRepository.findOne(99);System.out.println(employee);}
}

查看員工是否存在

@Testpublic void testExists() {Boolean result1 = employeeJpaRepository.exists(25);Boolean result2 = employeeJpaRepository.exists(130);System.out.println("Employee-25: " + result1);System.out.println("Employee-130: " + result2);}

JpaSpecificationExecutor接口

  • Specification封裝了JPA Criteria查詢條件

  • 沒有繼承其他接口。

自定義接口

這里要尤為注意,為什么我除了繼承JpaSpecificationExecutor還要繼承JpaRepository,就像前面說的,JpaSpecificationExecutor沒有繼承任何接口,如果我不繼承JpaRepository,那也就意味著不能繼承Repository接口,spring就不能進行管理,后面的自定義接口注入就無法完成。

package com.zzh.repository;import com.zzh.domain.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;public interface EmployeeJpaSpecificationExecutor extends JpaSpecificationExecutor<Employee>,JpaRepository<Employee,Integer> {
}

測試類

測試結果包含分頁,降序排序,查詢條件為年齡大于50

package com.zzh.repository;import com.zzh.domain.Employee;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import javax.persistence.criteria.*;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:beans-new.xml"})
public class EmployeeJpaSpecificationExecutorTest {@Autowiredprivate EmployeeJpaSpecificationExecutor employeeJpaSpecificationExecutor;/*** 分頁* 排序* 查詢條件: age > 50*/@Testpublic void testQuery() {Sort.Order order = new Sort.Order(Sort.Direction.DESC, "id");Sort sort = new Sort(order);Pageable pageable = new PageRequest(0, 5, sort);/*** root:查詢的類型(Employee)* query:添加查詢條件* cb:構建Predicate*/Specification<Employee> specification = new Specification<Employee>() {@Overridepublic Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) {Path path = root.get("age");return cb.gt(path, 50);}};Page<Employee> page = employeeJpaSpecificationExecutor.findAll(specification, pageable);System.out.println("查詢的總頁數:"+ page.getTotalPages());System.out.println("總記錄數:"+ page.getTotalElements());System.out.println("當前第幾頁:" + page.getNumber() + 1);System.out.println("當前頁面對象的集合:"+ page.getContent());System.out.println("當前頁面的記錄數:"+ page.getNumberOfElements());}}

可以看到id是從50開始,而不是100,因為設定了查詢條件age>50

917807-20170524092721794-955880776.png


總結

本篇文章首先介紹以原始的jdbc方式和Spring JdbcTemplate進行數據庫相關操作,接著講解了Spring Data Jpa的Repository接口和增刪查改有關的注解,最后介紹了Repository的一些子接口相關的crud,分頁和排序。

GitHub地址:SpringDataJpa

轉載于:https://www.cnblogs.com/zhaozihan/p/6884077.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/392697.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/392697.shtml
英文地址,請注明出處:http://en.pswp.cn/news/392697.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

azure多功能成像好用嗎_Azure持久功能簡介:模式和最佳實踐

azure多功能成像好用嗎Authored with Steef-Jan Wiggers at Microsoft Azure由Microsoft Azure的Steef-Jan Wiggers撰寫 With Durable Functions, you can program a workflow and instantiate tasks in sequential or parallel order, or you can build a watch or support a…

leetcode 327. 區間和的個數(treemap)

給定一個整數數組 nums&#xff0c;返回區間和在 [lower, upper] 之間的個數&#xff0c;包含 lower 和 upper。 區間和 S(i, j) 表示在 nums 中&#xff0c;位置從 i 到 j 的元素之和&#xff0c;包含 i 和 j (i ≤ j)。 說明: 最直觀的算法復雜度是 O(n2) &#xff0c;請在此…

常用的工具函數

得到兩個數組的并集, 兩個數組的元素為數值或字符串//tools.js export const getUnion (arr1, arr2) > {return Array.from(new Set([...arr1, ...arr2])) }//調用頁面 import { getUnion } from /libs/toolsthis.getUnion getUnion([1,2,3,5],[1,4,6]) //(6) [1, 2, 3,…

git 常用commands(轉)

常用 Git 命令清單 作者&#xff1a; 阮一峰 日期&#xff1a; 2015年12月 9日 我每天使用 Git &#xff0c;但是很多命令記不住。 一般來說&#xff0c;日常使用只要記住下圖6個命令&#xff0c;就可以了。但是熟練使用&#xff0c;恐怕要記住60&#xff5e;100個命令。 下面是…

Win2003磁盤分區調整

引用如下&#xff1a; 可能大家都知道&#xff0c;在Windows Server 2003下&#xff0c;普通版本的分區魔術師是無法運行的&#xff0c;而Windows內置的命令行工具Diskpart則能勝任分區魔術師的大部分工作&#xff0c;它的功能非常強大。輸入Diskpart后&#xff0c;將顯示如圖所…

檢查集群狀態命令_輕松管理Kubernetes集群的7個工具

Kubernetes正在不斷加快在云原生環境的應用&#xff0c;但如何以統一、安全的方式對運行于任何地方的Kubernetes集群進行管理面臨著挑戰&#xff0c;而有效的管理工具能夠大大降低管理的難度。K9sk9s是基于終端的資源儀表板。它只有一個命令行界面。無論在Kubernetes儀表板Web …

leetcode 122. 買賣股票的最佳時機 II(貪心算法)

給定一個數組&#xff0c;它的第 i 個元素是一支給定股票第 i 天的價格。 設計一個算法來計算你所能獲取的最大利潤。你可以盡可能地完成更多的交易&#xff08;多次買賣一支股票&#xff09;。 注意&#xff1a;你不能同時參與多筆交易&#xff08;你必須在再次購買前出售掉…

前端繪制繪制圖表_繪制圖表(第2頁):JavaScript圖表庫的比較

前端繪制繪制圖表by Mandi Cai蔡曼迪 繪制圖表(第2頁)&#xff1a;JavaScript圖表庫的比較 (Charting the waters (pt. 2): a comparison of JavaScript charting libraries) 深入研究D3.js&#xff0c;Dygraphs&#xff0c;Chart.js和Google Charts (A deep dive into D3.js,…

python 3.6.5 pip_在Windows 10 + Python 3.6.5 中用 pip 安裝最新版 TensorFlow v1.8 for GPU

聲明什么cuDNN之類的安裝&#xff0c;應該是毫無難度的&#xff0c;按照官網的教程來即可&#xff0c;除非。。。像我一樣踩了狗屎運。咳咳&#xff0c;這些問題不是本文的關鍵。本文的關鍵是解決pip安裝tensorflow gpu版的問題。安裝環境操作系統&#xff1a;64位的Windows 10…

模板進階——模板實參推斷

一、關鍵點 模板實參&#xff1a;模板參數T的實例類型&#xff0c;如int、string等 模板實參推斷&#xff1a;從函數實參來確定模板實參的過程 模板類型參數與類型轉換&#xff1a;const的轉換、數組/函數到指針的轉換 顯式模板實參&#xff1a;當模板參數類型并未出現在函數參…

leetcode 973. 最接近原點的 K 個點(排序)

我們有一個由平面上的點組成的列表 points。需要從中找出 K 個距離原點 (0, 0) 最近的點。 &#xff08;這里&#xff0c;平面上兩點之間的距離是歐幾里德距離。&#xff09; 你可以按任何順序返回答案。除了點坐標的順序之外&#xff0c;答案確保是唯一的。 示例 1&#xf…

ios 打開揚聲器

[[UIDevice currentDevice] setProximityMonitoringEnabled:YES]; AVAudioSession *audioSession [AVAudioSession sharedInstance]; //默認情況下揚聲器播放 [audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthe…

sqlserver 批量處理數據

目前我覺得有兩種方法可以用作批量數據的處理&#xff0c;也算比較靠譜的吧&#xff1a;sqlbulkcopy 和利用表值函數。 1.sqlbulkcopy是dotnet中的一個用來處理大批量插入數據的&#xff0c;具體用法如下&#xff1a; using (SqlConnection conSave new SqlConnection(Config.…

區塊鏈編程語言_區塊鏈開發中使用的最受歡迎的編程語言

區塊鏈編程語言by Michael Draper通過邁克爾德雷珀(Michael Draper) We’re currently in the midst of a new burgeoning industry with blockchain development.我們目前正處于區塊鏈開發的新興行業中。 Blockchain technology is very much in a nascent stage, however t…

vscode 模糊部分代碼_本周 GitHub 速覽:您的代碼有聲兒嗎?(Vol.38)

作者&#xff1a;HelloGitHub-小魚干摘要&#xff1a;還記得花式夸贊程序員的彩虹屁插件 vscode-rainbow-fart 嗎&#xff1f;它后續有人啦&#xff01;JazzIt 同它的前輩 vscode-rainbow-fart 一樣&#xff0c;是一個能讓代碼“發聲”的工具&#xff0c;它會在腳本運行成功或者…

有趣的鏈接

1行命令實現人臉識別&#xff1a;https://linux.cn/article-9003-1.html轉載于:https://blog.51cto.com/10704527/1983007

webpack基礎使用Loader(三)

loaders:[ { test:/\.js$/, loader:babel-loader, exclude:__dirname"/node_modules/", //排除打包的范圍&#xff08;需要絕對路徑&#xff09; include:__dirname"src",//指定打包的范圍&#xff08;需要絕對路徑&#xff09; query:{ …

Flutter VS React Native –為什么我認為Flutter最適合移動應用程序開發

This isn’t the type of article you might think it’s going to be. I’m not going to list the pros and cons of every framework and I am not going to do a comparative analysis of performance. 這不是您可能會想到的文章類型。 我不會列出每個框架的優缺點&#xf…

python 2.7 error: Microsoft Visual C++ 9.0 is required

參考&#xff1a;https://stackoverflow.com/questions/43645519/microsoft-visual-c-9-0-is-required 解決方法&#xff1a; 下載并安裝Microsoft Visual C Compiler for Python 2.7&#xff1a; Microsoft Visual C Compiler for Python 2.7 轉載于:https://www.cnblogs.com/…

python內置支持集合運算嗎_Python中的集合支持交、并運算

Python中的集合支持交、并運算答&#xff1a;√新冠肺炎患者潛伏期的傳染性最強答&#xff1a;對在運動的組接中&#xff0c;鏡頭組接一個基本的原則是()、()。答&#xff1a;動接動 靜接靜在中指背,距指甲根中點1分許稱答&#xff1a;老龍庫存控制屬于生產管理而不是物流管理的…