一、SpringData是什么
SpringData是Spring大家族中一个成员项目,从名字就可以知道这个框架是针对数据访问层设计的一个框架。看一下官方是如何表述的:SpringData的任务是为数据访问提供一个熟悉的、一致性的基于spring编程模型,同时仍然保留底层数据存储的特殊性。使得数据访问技术变得简单,包括对关系型、非关系型、map-reduce、以及基于云的数据服务。
二、核心模块有哪些?
Spring Data Commons SpringData的基础通用模块 Spring Data JDBC 支持JDBC的模块 Spring Data JDBC Ext 支持JDBC的一些特定扩展 Spring Data JPA 支持JPA Spring Data KeyValue Spring Data LDAP Spring Data MongoDB Spring Data Redis Spring Data REST Spring Data for Apache Cassandra Spring Data for Apace Geode Spring Data for Apache Solr Spring Data for Pivotal GemFire
三、spingData JPA
1、使用到的依赖
<!--spring data jpa--> <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>
2、其他的配置
<?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.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!--1 配置数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="username" value="root"/> <property name="password" value="mysql"/> <property name="url" value="jdbc:mysql:///spring_data"/> </bean> <!--2 配置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.imooc"/> <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> <!--3 配置事务管理器--> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!--4 配置支持注解的事务--> <tx:annotation-driven transaction-manager="transactionManager"/> <!--5 配置spring data--> <jpa:repositories base-package="com.imooc" entity-manager-factory-ref="entityManagerFactory"/> <context:component-scan base-package="com.imooc"/> </beans>
四、Repository接口
4.1Repository接口是spring Data的核心接口,不提供任何方法。
public interface Repository<T, ID extends Serializable>
第一个参数T代表实体类,第二个参数是T中ID的类型,String或者Integer都是可以的
可以使用@RepositoryDefinition注解达到同样的效果。
@RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class)
4.2Repository类的定义
public interface Repository<T, ID extends Serializable> { }
1)是一个空接口,标记接口(没有包含方法声明的接口)
2)如果是定义的接口employee继承了该接口,那么会被spring进行管理。
如果定义的接口没有继承该接口,会报如下错误
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'employeeService': Unsatisfied dependency expressed through field 'employeeRepository';
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type
3) 可以使用@RepositoryDefinition注解达到同样的效果。
@RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class)
五、子接口介绍
1、CrudRepository
继承Repository,实现了CRUD相关的方法。
<S extends T> S save(S var1); <S extends T> Iterable<S> save(Iterable<S> var1); T findOne(ID var1); boolean exists(ID var1); Iterable<T> findAll(); Iterable<T> findAll(Iterable<ID> var1); long count(); void delete(ID var1); void delete(T var1); void delete(Iterable<? extends T> var1); void deleteAll();
2、PagingAndSortingRepository
分页和排序的接口
Iterable<T> findAll(Sort var1);
Page<T> findAll(Pageable var1);
3、JpaRepository
继承自PagingAndSortingRepository
List<T> findAll(Sort var1); List<T> findAll(Iterable<ID> var1); <S extends T> List<S> save(Iterable<S> var1); void flush(); <S extends T> S saveAndFlush(S var1); void deleteInBatch(Iterable<T> var1); void deleteAllInBatch(); T getOne(ID var1);
六、Repository中查询方法定义规则和使用
1、了解Spring Data中查询方法名称的定义规则
例如方法名为:findByNameStartingWithAndAgeLessThan
@Test public void testFindByNameInOrAgeLessThan() { List<String> names = new ArrayList<String>(); names.add("test1"); names.add("test2"); names.add("test3"); List<Employee> employees = employeeRepository.findByNameInOrAgeLessThan(names, 22); for (Employee employee : employees) { System.out.println("id:" + employee.getId() + " , name:" + employee.getName() + " ,age:" + employee.getAge()); } }
弊端:1)方法可能会因为查询条件的增多而变得很长
2)复杂查询很难实现
2、Query注解的使用
不需要遵循查询方法命名规则,可以自由定义
只需要将@query定义在Reponsitory中的方法上即可
命名参数以及索引参数的使用。
索引参数使用举例:
@Query("select o from Employee o where o.name=?1 and o.age=?2") public List<Employee> queryParams1(String name, Integer age);
命名参数使用举例:
@Query("select o from Employee o where o.name like %:name%") public List<Employee> queryLike2(@Param("name")String name);
原生SQL查询 :
@Query(nativeQuery = true, value = "select count(1) from employee") public long getCount();
七、更新及删除操作整合事务的使用
1、@Modifying注解使用
@Modifying @Query("update Employee o set o.age = :age where o.id = :id") public void update(@Param("id")Integer id, @Param("age")Integer age);
2、@Modifying结合@Query注解执行更新操作
3、@Transactional在SpringData中的使用
事务在spring Data中的使用
1)事务一般是在Service层
2)@query、@Modifying、@Transactional的综合使用
八、SpringData深入学习
1、CrudRepository
只需要声明一下接口即可
public interface EmployeeCrudRepository extends CrudRepository<Employee,Integer>
2、PagingAndSortingRepository
该接口包含分页和排序功能
带排序的查询:findAll(Sort sort)
带排序的分页查询:findAll(Pageable pageable)
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID>
使用实践
public void testPageAndSort(){ Sort.Order order = new Sort.Order(Sort.Direction.DESC,"age"); Sort sort = new Sort(order); Pageable pageable = new PageRequest(0,5,sort); Page<Employee> employeePage = employeePagingAndSortingRepository.findAll(pageable); System.out.println("查询的总页数:"+employeePage.getTotalPages() ); System.out.println("查询的条数:"+employeePage.getTotalElements() ); System.out.println("查询的当前页的集合:"+employeePage.getContent() ); System.out.println("查询当前是第几页:"+employeePage.getNumber() ); System.out.println("查询当前页的记录数:"+employeePage.getNumberOfElements() ); }
3、JpaRepository
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>
Specification封装了JPA Criteria查询条件
public void testQuery(){ Sort.Order order = new Sort.Order(Sort.Direction.DESC,"id"); Sort sort = new Sort(order); Pageable pageable = new PageRequest(0,5,sort); Specification<Employee> employeeSpecification = new Specification<Employee>() { public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { Path path = root.get("age"); return criteriaBuilder.ge(path,50); } }; Page<Employee> employeePage = employeeJpaSpecificationRepository.findAll(employeeSpecification,pageable); // Page<Employee> employeePage = employeeJpaSpecificationRepository.findAll(pageable); System.out.println("查询的总页数:"+employeePage.getTotalPages() ); System.out.println("查询的条数:"+employeePage.getTotalElements() ); System.out.println("查询的当前页的集合:"+employeePage.getContent() ); System.out.println("查询当前是第几页:"+employeePage.getNumber() ); System.out.println("查询当前页的记录数:"+employeePage.getNumberOfElements() ); }