SpringData详解

1.什么是SpringData?java

Spring Data 项目的目的是为了简化构建基于 Spring 框架应用的数据访问计数,包括非关系数据库、Map-Reduce 框架、云数据服务等等;另外也包含对关系数据库的访问支持。spring

Spring Data 包含多个子项目:sql

Commons - 提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化
Hadoop - 基于 Spring 的 Hadoop 做业配置和一个 POJO 编程模型的 MapReduce 做业
Key-Value  - 集成了 Redis 和 Riak ,提供多个经常使用场景下的简单封装
Document - 集成文档数据库:CouchDB 和 MongoDB 并提供基本的配置映射和资料库支持
Graph - 集成 Neo4j 提供强大的基于 POJO 的编程模型
Graph Roo AddOn - Roo support for Neo4j
JDBC Extensions - 支持 Oracle RAD、高级队列和高级数据类型
JPA - 简化建立 JPA 数据访问层和跨存储的持久层功能
Mapping - 基于 Grails 的提供对象映射框架,支持不一样的数据库
Examples - 示例程序、文档和图数据库
Guidance - 高级文档数据库

看了这么多专业的介绍,其实Spring Data项目旨在为你们提供一种通用的编码模式,统一咱们的API。编程

2.HelloWorld展现
学习任何东西,从一个简单易懂的DEMO学起,会很是重要,下面先来看一个简单的HelloWorlddemo
直接看一下Dao层吧!app

[java] view plain copy  
<span style="font-family:Comic Sans MS;font-size:18px;">/**      框架

  • @FileName: PersonRepotory.java    
  • @Package:com.tgb.springdata.Entity    
  • @Description: TODO   
  • @author: LUCKY     
  • @date:2015年11月8日 下午6:38:58    
  • @version V1.0      

*/  
package com.tgb.springdata.Entity;  
  
import java.util.Date;  
import java.util.List;  
  
import org.hibernate.type.TrueFalseType;  
import org.springframework.data.jpa.repository.JpaRepository;  
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;  
import org.springframework.data.jpa.repository.Modifying;  
import org.springframework.data.jpa.repository.Query;  
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;  
import org.springframework.data.repository.CrudRepository;  
import org.springframework.data.repository.PagingAndSortingRepository;  
import org.springframework.data.repository.Repository;  
import org.springframework.data.repository.query.Param;  
  
/**   dom

  • @ClassName: PersonRepotory    
  • @Description: TODO   
  • @author: LUCKY   
  • @date:2015年11月8日 下午6:38:58      

*/  
  
/* ide

  • 1.Repository是一个空接口,便是一个标记接口 
  • 2.若咱们定义的接口继承了Repository,则该接口会被IOC容器识别为一个Repository Bean 
  • 注入到IOC容器中,进而能够在该接口中定义知足必定规则的接口 
  • 3.实际上也能够经过一个注解@RepositoryDefination 注解来替代Repository接口 

*/  
/* oop

  • 在Repository子接口中声明方法 
  • 1.不是随便声明的,而须要符合必定的规范 
  • 2.查询方法以find|read|get开发 
  • 3.涉及条件查询,条件的属性须要定义关键字链接 
  • 4.要注意的额是,条件的属性以字母大写 
  • 5.支持属性的级联查询,若当前类有符合条件的属性,则优先使用,则不使用级联属性 
  • 若须要使用级联属性,则属性之间使用——进行链接 

*/  
//@RepositoryDefinition(domainClass=Person.class,idClass=Integer.class)  
public interface PersonRepotory  extends JpaRepository<Person,Integer>,JpaSpecificationExecutor<Person>,PersonDao  {  
  
      
    //根据lastname,来获取对应的Person  
    Person getByLastName(String lastName);  
      
    //Where lastName like ?% and id<?  
    List<Person> getByLastNameStartingWithAndIdLessThan(String lastName,Integer id);  
      
      
    //Where lastName like ?% and id<?  
    List<Person> getByLastNameEndingWithAndIdLessThan(String lastName,Integer id);  
      
    //where email In(?,?,?) Or birth < ?  
    List<Person> getByEmailInOrBirthLessThan(List<String> emails,Date birth);  
      
    //where a.id>?  
    List<Person> getByAddressIdGreaterThan(Integer id);  
      
    //查询id值最大的那个person  
    //使用@Query注解能够自定义JPQL语句,语句能够实现更灵活的查询  
    @Query("SELECT p FROM Person p WHERE p.id=(SELECT max(p2.id) FROM Person p2)")  
    Person getMaxIdPerson();  
      
    //为@Query注解传递参数的方式1:使用占位符  
    @Query("SELECT P FROM Person P where P.lastName=?1 AND P.email=?2")  
    List<Person> testQueryAnnotationParams1(String lastName,String email);  
      
      
      
    //为@Query注解传递参数的方式2:使用命名参数方式  
        @Query("SELECT P FROM Person P where P.lastName=:lastName AND P.email=:email")  
        List<Person> testQueryAnnotationParams2(@Param("email")String email,@Param("lastName")String lastName);  
          
          
        //Spring Data 运行在占位符上添加%%  
        @Query("select p from Person p where p.lastName like %?1% or p.email like %?2%")  
        List<Person> testQueryAnnotationLikeParam(String lastName,String email);  
          
        //设置nativeQuery=true 可使用原生的sql查询  
        @Query(value="SELECT count(id) FROM jpa_persons",nativeQuery=true)  
        public long getTotalCount();  
          
          
        //能够经过自定义的JPQL 完成update和delete操做,注意:JPQL不支持Insert操做  
        //在@Query注解中编写JPQL语句,但必须使用@Modify进行修饰,以通知SpringData,这是一个Update或者Delete  
        //Update或者delete操做,须要使用事务,此时须要定义Service层,在service层的方法上添加事务操做  
        //默认状况下,SpringData的每一个方法上有事务,但都是一个只读事务,他们不能完成修改操做  
        @Modifying  
        @Query("update Person p set p.email=:email where id=:id")  
        void updatePersonEmail(@Param("id")Integer id,@Param("email")String email);  
          
          
}  
</span>  

在Spring Data JPA中经过继承接口就能够了,下面来看一下是如何来调用的

[java] view plain copy  
<span style="font-family:Comic Sans MS;font-size:18px;">/**      

  • @FileName: SpringDataTest.java    
  • @Package:com.tgb.test    
  • @Description: TODO   
  • @author: LUCKY     
  • @date:2015年11月8日 下午5:35:37    
  • @version V1.0      

*/  
package com.tgb.test;  
  
import static org.junit.Assert.*;  
  
import java.sql.SQLException;  
import java.util.ArrayList;  
import java.util.Arrays;  
import java.util.Date;  
import java.util.List;  
  
import javax.persistence.criteria.CriteriaBuilder;  
import javax.persistence.criteria.CriteriaQuery;  
import javax.persistence.criteria.Path;  
import javax.persistence.criteria.Predicate;  
import javax.persistence.criteria.Root;  
import javax.sql.DataSource;  
  
import org.junit.Test;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
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.domain.Sort.Direction;  
import org.springframework.data.domain.Sort.Order;  
import org.springframework.data.jpa.domain.Specification;  
  
import com.tgb.springdata.Entity.Person;  
import com.tgb.springdata.Entity.PersonRepotory;  
import com.tgb.springdata.Service.PersonService;  
  
/**   

  • @ClassName: SpringDataTest    
  • @Description: TODO   
  • @author: LUCKY   
  • @date:2015年11月8日 下午5:35:37      

*/  
public class SpringDataTest {  
  
    private PersonRepotory personRepotory=null;  
    private PersonService personService;  
    private ApplicationContext ctx=null;  
    {  
        ctx=new ClassPathXmlApplicationContext("applicationContext.xml");  
        personRepotory=ctx.getBean(PersonRepotory.class);  
        personService=ctx.getBean(PersonService.class);  
    }  
      
      
    @Test  
    public void testKeyWorlds(){  
        List<Person> persons=personRepotory.getByLastNameStartingWithAndIdLessThan("BB", 10);  
        System.out.println(persons);  
          
        List<Person> persons1=personRepotory.getByLastNameEndingWithAndIdLessThan("BB", 10);  
        System.out.println(persons);  
        System.out.println(persons1);  
          
        persons=personRepotory.getByEmailInOrBirthLessThan(Arrays.asList("aa@qq.com","bb@qq.com"),new Date());  
        System.out.println(persons.size());  
    }  
      
      
      
      
      
    @Test  
    public void testDataSource() throws SQLException{  
        DataSource dataSource=ctx.getBean(DataSource.class);  
        System.out.println(dataSource.getConnection());  
    }  
      
    @Test  
    public void TestJpa(){  
          
    }  
      
    @Test  
    public void testKeyWorlds2(){  
        List<Person> persons=personRepotory.getByAddressIdGreaterThan(1);  
        System.out.println(persons);  
    }  
      
    @Test  
    public void testQueryAnnotation(){  
        Person person=personRepotory.getMaxIdPerson();  
//      System.out.println(person);  
          
        List<Person> persons=personRepotory.testQueryAnnotationParams1("AA", "bb");  
        System.out.println(persons);  
          
        List<Person> persons1=personRepotory.testQueryAnnotationParams2("bb", "AA");  
        System.out.println(persons1);  
    }  
      
      
    @Test  
    public void testModifing(){  
//      personRepotory.updatePersonEmail(1, "@@qq.com");  
        personService.updatePersonEmail("aa@aa", 1);  
    }  
      
    @Test  
    public void testQueryLikeAnnotationParam(){  
        List<Person> persons=personRepotory.testQueryAnnotationLikeParam("%AA%", "%b%");  
        System.out.println(persons);  
          
        long count=personRepotory.getTotalCount();  
        System.out.println(count);  
    }  
      
      
      
      
    @Test  
    public void HelloWorldSpringData(){  
        PersonRepotory personRepotory=ctx.getBean(PersonRepotory.class);  
        System.out.println(personRepotory.getClass().getName());  
        Person person=personRepotory.getByLastName("AA");  
        System.out.println(person);  
          
        }  
      
      
    @Test  
    public void testCrudRepository()  
    {  
        List<Person> persons=new ArrayList<Person>();  
        for (int i = 1; i < 10000; i++) {  
            Person person=new Person();  
            person.setBirth(new Date());  
            person.setEmail("@2"+i+" com");  
            persons.add(person);  
        }  
          
        long startTime=System.currentTimeMillis();  
        personService.savePersons(persons);  
        long endTime=System.currentTimeMillis();  
        System.out.println((endTime-startTime)/1000);  
    }  
      
      
    @Test  
    public void testPagingAndSortingRespository(){  
        //pageNumber是从0开始的  
        int pageNumber=4;  
        int pageSize=5;  
        //PageAble 接口一般用的是PageRequest实现类,其中封装了须要分页的信息  
        //排序相关的,sor封装了排序的信息  
        Order order1=new Order(Direction.DESC, "id");  
          
        Order order2=new Order(Direction.DESC, "email");  
        Sort sort=new Sort(order1,order2);  
          
          
        Pageable pageable=new PageRequest(pageNumber, pageSize,sort);  
        Page<Person> page=personRepotory.findAll(pageable);  
        System.out.println("总记录数"+page.getTotalElements());  
        System.out.println("当前第几页"+page.getNumber());  
        System.out.println("总页数"+page.getTotalPages());  
        System.out.println("当前页面的List"+page.getContent());  
        System.out.println("当前页面的记录数"+page.getNumberOfElements());  
    }  
      
      
    @Test  
    public void testJpaRepository(){  
        Person person=new Person();  
        person.setBirth(new Date());  
        person.setEmail("aa");  
        person.setLastName("xyz");  
        personRepotory.saveAndFlush(person);  
          
          
    }  
      
      
    /* 
     * 实现带查询条件的分页效果 id>5 
     * 调用JpaSpecificationExecutor的page<T> findAll(Speciation<T>,PageAble pageable) 
     * specification:封装了JPA Criteria 查询的条件 
     * pageable:封装了请求分页的消息,例如pageno,pagesize,sort 
     */  
    @Test  
    public void testJpaSpeciationExecutor(){  
        int pageNo=0;  
        int pageSize=5;  
        PageRequest pageRequest=new PageRequest(pageNo, pageSize);  
        //一般使用Specification 的匿名内部类,  
        Specification<Person> specification=new Specification<Person>() {  
  
        /* 
         * @param root:表明的查询的实体类 
         * @param query:能够从中获得Root对象,即告知JPA Criteria查询要查询哪个实体类, 
         * 还能够来添加查询条件,还能够结合EntityManager对象获得最终查询的TypedQuery 对象 
         * @Param cb:criteriabuildre对象,用于建立Criteria相关的对象工程,固然能够从中获取到predicate类型 
         * @return:表明一个查询条件 
         */  
            @Override  
            public Predicate toPredicate(Root<Person> root,  
                    CriteriaQuery<?> query, CriteriaBuilder cb) {  
//              Path path=root.get("id");  
//              Predicate predicate=cb.gt(path, 5);  
                  
                Predicate p1=cb.like(root.get("id").as(String.class), "%"+"1"+"%");  
                Predicate p2=cb.equal(root.get("lastName").as(String.class), "sd");  
                Predicate p3=cb.like(root.get("email").as(String.class), "%s%");  
//              构建组合的Predicate示例:  
                Predicate p = cb.and(p3,cb.or(p1,p2));  
                  
                return p;  
            }  
              
        };  
          
        Page<Person> page=personRepotory.findAll(specification,pageRequest);  
      
        System.out.println("总记录数"+page.getTotalElements());  
        System.out.println("当前第几页"+page.getNumber());  
        System.out.println("总页数"+page.getTotalPages());  
        System.out.println("当前页面的List"+page.getContent());  
        System.out.println("当前页面的记录数"+page.getNumberOfElements());  
    }  
      
      
    @Test  
    public void testCustomRepositoryMethod(){  
        personRepotory.test();  
    }  
      
      
}  
</span>  

或许会感到奇怪,为什么Dao只单纯的是一个接口,没有实现类呢?其实这就是Spring Data JPA为咱们封装了,只要按照Spring Data JPA的规范来定义,就会自动为咱们生成一个默认的代理实现类。

3.Repository 接口

•基础的 Repository提供了最基本的数据访问功能,其几个子接口则扩展了一些功能。它们的继承关系以下: 
–Repository:仅仅是一个标识,代表任何继承它的均为仓库接口类
–CrudRepository:继承Repository,实现了一组CRUD相关的方法 
–PagingAndSortingRepository:继承CrudRepository,实现了一组分页排序相关的方法 
–JpaRepository:继承PagingAndSortingRepository,实现一组JPA规范相关的方法 
–自定义的 XxxxRepository须要继承 JpaRepository,这样的XxxxRepository接口就具有了通用的数据访问控制层的能力。
–JpaSpecificationExecutor:不属于Repository体系,实现一组JPACriteria查询相关的方法 

4.@Query 注解

•这种查询能够声明在 Repository方法中,摆脱像命名查询那样的约束,将查询直接在相应的接口方法中声明,结构更为清晰,这是Springdata 的特有实现。
//查询id值最大的那个person
//使用@Query注解能够自定义JPQL语句,语句能够实现更灵活的查询
@Query("SELECT p FROM Person p WHERE p.id=(SELECT max(p2.id) FROM Person p2)")
Person getMaxIdPerson();

5.@Modifying 注解

@Query 与 @Modifying这两个annotation一块儿声明,可定义个性化更新操做,例如只涉及某些字段更新时最为经常使用,示例以下

//能够经过自定义的JPQL 完成update和delete操做,注意:JPQL不支持Insert操做//在@Query注解中编写JPQL语句,但必须使用@Modify进行修饰,以通知SpringData,这是一个Update或者Delete//Update或者delete操做,须要使用事务,此时须要定义Service层,在service层的方法上添加事务操做//默认状况下,SpringData的每一个方法上有事务,但都是一个只读事务,他们不能完成修改操做@Modifying@Query("update Person p set p.email=:email where id=:id")void updatePersonEmail(@Param("id")Integer id,@Param("email")String email);

相关文章
相关标签/搜索