浅谈Spring Data如何简化数据操作的方法

Spring Data 概述

Spring Data

用于简化数据库访问,支持NoSQL 和 关系数据存储,其主要目标是使数据库的访问变得方便快捷。
SpringData 项目所支持 NoSQL 存储:
MongoDB (文档数据库)
Neo4j(图形数据库)
Redis(键/值存储)
Hbase(列族数据库)
SpringData 项目所支持的关系数据存储技术:
JDBC
JPA

Spring Data JPA

JPA Spring Data : 致力于减少数据访问层 (DAO) 的开发量. 开发者唯一要做的,就只是声明持久层的接口,其他都交给 Spring Data JPA 来帮你完成!

开发步骤

配置 Spring 整合 JPA

在 Spring 配置文件中配置 Spring Data,让 Spring 为声明的接口创建代理对象,配置了 \<jpa:repositories> 后,Spring 初始化容器时将会扫描 base-package 指定的包目录及其子目录,为继承 Repository 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,业务层便可以通过 Spring 自动封装的特性来直接使用该对象。

声明持久层的接口,该接口继承 Repository,Repository 是一个标记型接口,它不包含任何方法,如必要,Spring Data 可实现 Repository 其他子接口,其中定义了一些常用的增删改查,以及分页相关的方法。

在接口中声明需要的方法,Spring Data 将根据给定的策略来为其生成实现代码。

搭建环境

导包:

antlr-2.7.7.jar
c3p0-0.9.2.1.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar
dom4j-1.6.1.jar
hamcrest-core-1.3.jar
hibernate-c3p0-4.2.4.Final.jar
hibernate-commons-annotations-4.0.2.Final.jar
hibernate-core-4.2.4.Final.jar
hibernate-entitymanager-4.2.4.Final.jar
hibernate-jpa-2.0-api-1.0.1.Final.jar
javassist-3.15.0-GA.jar
jboss-logging-3.1.0.GA.jar
jboss-transaction-api_1.1_spec-1.0.1.Final.jar
junit-4.12.jar
mchange-commons-java-0.2.3.4.jar
mysql-connector-java-5.1.7-bin.jar
slf4j-api-1.6.1.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-data-commons-1.6.2.RELEASE.jar
spring-data-jpa-1.4.2.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar

applicationContext.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.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">
  <context:component-scan base-package="com.kernel.spring.data"/>
  <!--配置数据源-->
  <context:property-placeholder location="classpath:db.properties"/>
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClass}"/>
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
    <property name="user" value="${jdbc.user}"/>
    <property name="password" value="${jdbc.password}"/>
  </bean>
  <!--配置JPA的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.kernel.spring.data"/>
    <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.kernel.spring.data" entity-manager-factory-ref="entityManagerFactory"/>
</beans>

Repository 接口

Repository 接口是 Spring Data 的一个核心接口,不提供任何方法,只要遵循接口方法定义规范,就无需写实现类,与继承 Repository 接口等价的一种方式,就是在持久层接口上使用 @RepositoryDefinition 注解,并为其指定domainClass 和 idClass 属性。

Repository 的子接口

Repository: 仅仅是一个标识,表明任何继承它的均为仓库接口类。

CrudRepository: 继承 Repository,实现了一组 CRUD 相关的方法 。

PagingAndSortingRepository: 继承 CrudRepository,实现了一组分页排序相关的方法 。

JpaRepository: 继承 PagingAndSortingRepository,实现一组 JPA 规范相关的方法 。

自定义的 XxxxRepository 需要继承 JpaRepository,这样的 XxxxRepository 接口就具备了通用的数据访问控制层的能力。

JpaSpecificationExecutor: 不属于Repository体系,实现一组 JPA Criteria 查询相关的方法 。

Spring Data 方法定义规范

简单条件查询,查询某一个实体或者集合,查询方法以 get、find、read 开头,涉及条件查询时,条件的属性用关键字连接,条件属性以首字母大写。

例如

public interface PersonRepository extends Repository<Person, Integer> {
  Person getByLastName(String lastName);

  List<Person> getByLastNameStartingWithAndIdLessThan(String lastName, Integer id);

  List<Person> getByLastNameEndingWithAndIdLessThan(String lastName, Integer id);

  List<Person> getByEmailInAndAgeLessThan(List list, Integer id);

  List<Person> getByAddress_IdGreaterThan(Integer id);
}

Spring Data 支持的关键字

Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = 1?
Betwee findByStartDateBetween … where x.startDate between 1? and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1(parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1(parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> age) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

@Query 注解

这种查询可以声明在 Repository 方法中,摆脱像命名查询那样的约束,将查询直接在相应的接口方法中声明,结构更为清晰,这是 Spring Data 的特有实现。

索引参数:

索引值从1开始,查询中 ?x 的个数需要与方法形参个数相等,并且顺序也要一致。

@Query("SELECT p FROM Person p WHERE p.lastName = ?1 and p.age = ?2")
Person getByLastNameAndAge(String lastName, int age);

命名参数:

可以定义好参数名,赋值值采用 @Param(参数名),而不用管顺序。

@Query("SELECT p FROM Person p WHERE p.lastName = :lastName and p.id = :id")
Person getByLastNameAndId(@Param("id")int id, @Param("lastName")String lastName);

本地查询:

可以使用 @Query 执行本地查询,只要设置 nativeQuery 为 true。

@Query(value = "SELECT COUNT (id) FROM jpa_persons", nativeQuery = true)
long getTotalCount();

@Modifying 注解和事务

@Query 与 @Modifying 这两个注解一起使用,可以执行 UPDATE、DELETE 操作。

注意,UPDATE、DELETE 需要使用事务,因此需要定义在 Service 层。

事务:

Spring Data 提供了默认的事务处理方式,即所有的查询均为只读事务。

对于自定义的方法,如需改变 Spring Data 提供的事务方式,可以在方法上添加 @Transactional 注解。

进行多个 Repository 操作时,也应该使它们在同一个事务中处理,按照分层架构的思想,这部分属于业务逻辑层,因此,需要在 Service 层实现对多个 Repository 的调用,并在相应的方法上声明事务。

CrudRepository 接口

CrudRepository 接口提供了最基本的对实体类的添删改查操作
T save(T entity) 保存单个实体
Iterable<T> save(Iterable<? extends T> entities) 保存集合
T findOne(ID id) 根据id查找实体
boolean exists(ID id) 根据id判断实体是否存在
Iterable<T> findAll() 查询所有实体,不用或慎用
long count() 查询实体数量
void delete(ID id) 根据Id删除实体
void delete(T entity) 删除一个实体
void delete(Iterable<? extends T> entities) 删除一个实体的集合
void deleteAll() 删除所有实体,不用或慎用

PagingAndSortingRepository 接口

该接口提供了分页与排序功能

Iterable<T> findAll(Sort sort) 排序

Page<T> findAll(Pageable pageable) 分页查询(含排序功能)

@Test
public void testPagingAndSortingRespository(){
  int pageNo = 3;
  int pageSize = 5;
  Sort.Order order = new Sort.Order(Sort.Direction.DESC, "id");
  Sort.Order order1 = new Sort.Order(Sort.Direction.ASC, "email");
  Sort sort = new Sort(order,order1);
  PageRequest pageable = new PageRequest(pageNo, pageSize, sort);
  Page<Person> page = personRepository.findAll(pageable);
  System.out.println(page.getNumberOfElements());
  System.out.println(page.getContent());
}

JpaRepository 接口

该接口提供了JPA的相关功能

List<T> findAll() 查找所有实体

List<T> findAll(Sort sort) 排序、查找所有实体

List<T> save(Iterable<? extends T> entities) 保存集合

void flush() 执行缓存与数据库同步

T saveAndFlush(T entity) 强制执行持久化

void deleteInBatch(Iterable<T> entities) 删除一个实体集合

JpaSpecificationExecutor 接口

不属于Repository体系,实现一组 JPA Criteria 查询相关的方法

Specification:封装 JPA Criteria 查询条件。通常使用匿名内部类的方式来创建该接口的对象

@Test
public void testJpaSpecificationExecutor(){
  int pageNo = 3;
  int pageSize = 5;
  PageRequest pageable = new PageRequest(pageNo, pageSize);
  Specification<Person> specification = new Specification<Person>() {
    /**
       * @param root 代表查询的实体类
       * @param criteriaQuery 可以从中得到root对象,即告知 JPA Criteria 查询哪个实体类,
       *           还可以添加查询条件,还可以结合EntityManager对象得到最终查询的                  TypedQuery
       * @param criteriaBuilder 用于创建criteria工厂
       * @return Predicate类型,代表一个查询条件
       */
    @Override
    public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
      Predicate predicate = criteriaBuilder.ge(root.get("id"),5);
      return predicate;
    }
  };
  Page<Person> page = personRepository.findAll(specification, pageable);
  System.out.println(page.getNumberOfElements());
  System.out.println(page.getContent());
}

自定义 Repository 方法

为某一个 Repository 上添加自定义方法

创建一个 XXXDAO 接口,声明接口方法。

创建一个 XXXRepository 接口,并继承 XXXDAO 接口。

提供 XXXRepository 的实现类 XXXRepositoryImpl,并实现 XXXDAO 定义的接口方法。

实际上在使用 XXXRepository 的自定义方法时会调用 XXXRepositoryImpl 中的实现。

为所有的 Repository 都添加自实现的方法

创建一个 XXXRepository 接口,需要继承 创建一个 Repository 接口。

提供 XXXRepository 的实现类 XXXRepositoryImpl,且继承 SimpleJpaRepository,并提供方法的实现。

定义 JpaRepositoryFactoryBean 的实现类,使其生成 XXXRepository 的接口实现类的对象。

修改 \<jpa:repositories/> 节点的 factory-class 属性指向 JpaRepositoryFactoryBean 的实现类的全类名。

注意:

全局的扩展实现类不要用 Imp 作为后缀名,

或者为全局扩展接口添加 @NoRepositoryBean注解告知 SpringData 不要把其作为 Repository。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • springboot使用spring-data-jpa操作MySQL数据库

    我们在上一篇搭建了一个简单的springboot应用,这一篇将介绍使用spring-data-jpa操作数据库. 新建一个MySQL数据库,这里数据库名为springboot,建立user_info数据表,作为我们示例操作的表对象. user_info信息如下: DROP TABLE IF EXISTS `user_info`; CREATE TABLE `user_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(

  • Spring boot中使用Spring-data-jpa方便快捷的访问数据库(推荐)

    什么是JPA JPA(Java Persistence API)是Sun官方提出的Java持久化规范.它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据.他的出现主要是为了简化现有的持久化开发工作和整合ORM技术 Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作.它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA

  • Spring(AbstractRoutingDataSource)实现动态数据源切换示例

    一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目A中切换数据源,直接把数据写入项目B的数据库中.这种需求,在数据同步与定时任务中经常需要. 那么问题来了,该如何解决多数据源问题呢?不光是要配置多个数据源,还得能灵活动态的切换数据源.以spring+hibernate框架项目为例: 单个数据源绑定给sessionFactory,再在Dao层操作,若多个数据源的话,那不是就成了下图: 可见,sessionFactory都写死在了Dao层,若我再添加个数据

  • 详解基于Spring Boot与Spring Data JPA的多数据源配置

    由于项目需要,最近研究了一下基于spring Boot与Spring Data JPA的多数据源配置问题.以下是传统的单数据源配置代码.这里使用的是Spring的Annotation在代码内部直接配置的方式,没有使用任何XML文件. @Configuration @EnableJpaRepositories(basePackages = "org.lyndon.repository") @EnableTransactionManagement @PropertySource("

  • 详解Spring Data操作Redis数据库

    Redis是一种NOSQL数据库,Key-Value形式对数据进行存储,其中数据可以以内存形式存在,也可以持久化到文件系统.Spring data对Redis进行了很好的封装,用起来也是十分的得心应手.Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, h

  • 使用Spring Data Redis实现数据缓存的方法

    引言 目前很多系统为了解决数据读写的性能瓶颈,在系统架构设计中使用Redis实现缓存,Spring框架为了让开发人员更加方便快捷的使用Redis实现缓存,对Redis的操作进行了包装. 0.缓存 个人理解的缓存是指用于存储频繁使用的数据的空间,关注点是存储数据的空间和使用频繁的数据.缓存技术,简单的说就是先从缓存中查询数据是否存在,存在则直接返回,不存在再执行相应的操作获取数据,并将获取的数据存储到缓存中,它是一种提升系统性能的重要方法. 1.Redis Redis是一个开源的.内存存储key-

  • 使用Spring的AbstractRoutingDataSource实现多数据源切换示例

    最近因为项目需要在做两个项目间数据同步的需求,具体是项目1的数据通过消息队列同步到项目2中,因为这个更新操作还涉及到更新多个库的数据,所以就需要多数据源切换的操作.下面就讲讲在Spring中如何进行数据源切换.这里是使用AbstractRoutingDataSource类来完成具体的操作,AbstractRoutingDataSource是Spring2.0后增加的. 实现数据源切换的功能就是自定义一个类扩展AbstractRoutingDataSource抽象类,其实该相当于数据源DataSo

  • 浅谈Spring Data如何简化数据操作的方法

    Spring Data 概述 Spring Data 用于简化数据库访问,支持NoSQL 和 关系数据存储,其主要目标是使数据库的访问变得方便快捷. SpringData 项目所支持 NoSQL 存储: MongoDB (文档数据库) Neo4j(图形数据库) Redis(键/值存储) Hbase(列族数据库) SpringData 项目所支持的关系数据存储技术: JDBC JPA Spring Data JPA JPA Spring Data : 致力于减少数据访问层 (DAO) 的开发量.

  • 浅谈Spring Data Redis读不到设进去的值

    目录 目标 1 注意读.取一致性 解析 AbstractOperations#rawKey 修正 目标 精通 Spring Data Redis 操作流程. Spring Data提供了对市场上主流数据库支持: Spring Data Commons Spring Data JPA Spring Data KeyValue Spring Data LDAP Spring Data MongoDB Spring Data Redis Spring Data REST Spring Data for

  • 浅谈spring 常用注解

    我们不妨先将spring常用的注解按照功能进行分类 1 .将普通类加入容器形成Bean的注解 日常开发中主要使用到的定义Bean的注解包括(XML方式配置bean暂不讨论): @Component.@Repository.@Service.@Controller.@Bean 其中@Component.@Repository.@Service.@Controller实质上属于同一类注解,用法相同,功能相同,区别在于标识组件的类型.当一个组件代表数据访问层(Dao)时,你可以给它加上@Reposit

  • 浅谈Spring Session工作原理

    目录 1.引入背景 2.使用方法 3.工作流程 4.缓存机制 5.事件订阅 6.总结 1.引入背景 HTTP协议本身是无状态的,为了保存会话信息,浏览器Cookie通过SessionID标识会话请求,服务器以SessionID为key来存储会话信息.在单实例应用中,可以考虑应用进程自身存储,随着应用体量的增长,需要横向扩容,多实例session共享问题随之而来. 应用部署在Tomcat时,session是由Tomcat内存维护,如果应用部署多个实例,session就不能共享.Spring Ses

  • 浅谈spring中isolation和propagation的用法

    可以在XML文件中进行配置,下面的代码是个示意代码 <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" isolation="READ_COMMITTED"/>增加记录的方法 <t

  • 浅谈Spring中单例Bean是线程安全的吗

    Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究. Spring 的 bean 作用域(scope)类型 1.singleton:单例,默认作用域. 2.prototype:原型,每次创建一个新对象. 3.request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下. 4.session:会话,同一个会

  • 浅谈Spring Bean的基本配置

    一.Spring中set方法的注入 User实体 @Data //lombok提供的有参构造 @AllArgsConstructor lombok提供的无参构造 @NoArgsConstructor public class User { private int id; private String name; private int age; private String sex; private String birthday; } beanFactory.xml <bean id="

  • 浅谈Python数学建模之数据导入

    目录 一.数据导入是所有数模编程的第一步 二.在程序中直接向变量赋值 2.1.为什么直接赋值? 2.2.直接赋值的问题与注意事项 三.Pandas 导入数据 3.1.Pandas 读取 Excel 文件 3.2.Pandas 读取 csv 文件 3.3.Pandas 读取文本文件 3.4.Pandas 读取其它文件格式 四.数据导入例程 一.数据导入是所有数模编程的第一步 编程求解一个数模问题,问题总会涉及一些数据. 有些数据是在题目的文字描述中给出的,有些数据是通过题目的附件文件下载或指定网址

  • 浅谈Spring嵌套事务是怎么回滚的

    目录 源码解析 TransactionAspectSupport.invokeWithinTransaction() 内层事务 TransactionAspectSupport.completeTransactionAfterThrowing() AbstractPlatformTransactionManager rollback() DataSourceTransactionManager#doSetRollbackOnly DataSourceTransactionObject#setRo

随机推荐