Spring-Data-JPA快速使用.docx

上传人:scccc 文档编号:12065057 上传时间:2021-12-01 格式:DOCX 页数:29 大小:192.01KB
返回 下载 相关 举报
Spring-Data-JPA快速使用.docx_第1页
第1页 / 共29页
Spring-Data-JPA快速使用.docx_第2页
第2页 / 共29页
Spring-Data-JPA快速使用.docx_第3页
第3页 / 共29页
Spring-Data-JPA快速使用.docx_第4页
第4页 / 共29页
Spring-Data-JPA快速使用.docx_第5页
第5页 / 共29页
点击查看更多>>
资源描述

《Spring-Data-JPA快速使用.docx》由会员分享,可在线阅读,更多相关《Spring-Data-JPA快速使用.docx(29页珍藏版)》请在三一文库上搜索。

1、Spring Data JPA快速启动目录Spring Data JPA快速启动11概述12 Spring Data JPA使用12.1实体类规范:22.2 Dao接口规范:22.3 自定义查询42.4 配置文件规范62.5事务处理92.6 为接口中的部分方法提供自定义实现92.7 锁102.8 应用场景以及优点112.9 JPA的缺陷:111概述Spring Data JPA 是Spring Data 家族的提供的一个持久层框架,可以自动创建dao实现类和自定义查询,简化了持久层代码。推荐精选2 Spring Data JPA使用使用Spring Data JPA只需要3个步骤:(1)声明持

2、久层的接口,该接口继承 Repository,Repository 是一个标记型接口,它不包含任何方法,当然如果有需要,Spring Data 也提供了若干 Repository 子接口,其中定义了一些常用的增删改查,以及分页相关的方法。(2)在接口中声明需要的业务方法。Spring Data 将根据给定的策略来为其生成实现代码。(3)在 Spring 配置文件中增加一行声明,让 Spring 为声明的接口创建代理对象。配置了 <jpa:repositories> 后,Spring 初始化容器时将会扫描 base-package 指定的包目录及其子目录,为继承 Repository

3、 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,业务层便可以通过 Spring 自动封装的特性来直接使用该对象。此外,<jpa:repository> 还提供了一些属性和子标签,便于做更细粒度的控制。可以在 <jpa:repository> 内部使用 <context:include-filter>、<context:exclude-filter> 来过滤掉一些不希望被扫描到的接口。2.1实体类规范:实体类均使用注解进行配置,常用注解描述如下,其他请参考JPA配置规范:Entity:在bean的最上面使用,使实体bea

4、n映射到数据库中 . Table(name="tableName"):指定实体bean映射到数据库中的表名. Id GeneratedValue(strategy=GenerationType.AUTO) Id:指定实体bean在数据库表的实体标识属性 Strategy:id的生成策略. GenerationType.AUTO:自动(默认值,可以不设定) GenerationType.IDENTITY:数据库的id自增长(Oracle不支持) GenerationType. SEQUENCE:序列化(Mysql不支持) GenerationType.TABLE:表生成 推荐

5、精选Column(length=20,nullable=false,name="") :字段属性注释 Length:指定字段的长度 Nullable:是否为空.false:不为空;true:空 Name:指定字段映射到表的列名Temporal(TemporalType.DATE):指定类型为时间的字段属性的映射 DATE:日期,不包括时间.1985-09-09 TIME:时间,没有日期.23:44:00 TIMESTAMP:时间戳,包括日期和时间 1985-09-09 23:44:00 Enumerated(EnumType.STRING):枚举类型属性的映射 EnumTy

6、pe.STRING:保存枚举类型数据的字符类型数据到数据库 EnumType.ORDINAL:保存枚举类型数据的索引值到数据库 Lob:大文本字段(String)和二进制数组类型字段(Byte)使用它,对应数据库的大文本类型.Transient : 属性不跟数据库表进行映射使用Transient注解 Basic(fetch=FetchType.LAZY): 延时加载数据使用Basic注解中的FatchType:LAZY 懒加载;EAGER 立即2.2 Dao接口规范:Dao接口需要继承BaseDaoe.g:public interface PersonDao extends BaseDao&l

7、t;Person, Long>Person:Dao对应实体类类型Long:Dao对应实体类主键ID类型import java.io.Serializable;推荐精选import java.util.List;import org.springframework.data.domain.Page;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.data.repository.Repository;pu

8、blic interface BaseDao<T, ID extends Serializable> extends Repository<T, ID> BaseDao中提供了若干默认方法,可以直接进行调用,描述如下:1、 public <S extends T> List<S> save(Iterable<S> entities)/批量新增或编辑2、 public T save(T entity); / 保存或更新2、public T delete(T entity); / 根据ID删除3、public T findOne(ID i

9、d); / 根据ID查询4、public boolean exists(ID id); / 根据ID查找是否存在5、public List<T> findAll(); / 查询所有6、public List<T> findAll(Iterable<ID> ids); / 根据ID集合查找推荐精选7、public long count(); / 查询记录总数8、public Page<T> findAll(Pageable pageable); / 分页查询参数pageable:可以传递new PageRequest(0, 10)0表示第一页10表

10、示每页10条数据返回值Page对象使用:当前页:getNumber();每页显示条目数:getSize();总页数:getTotalPages();结果集总数量:getTotalElements();是否是首页:isFirstPage();是否是末页:isLastPage();是否有上一页:hasPreviousPage();是否是下一页:hasNextPage();查询结果集:getContent();9、public List<T> findAll(Sort sort); / 排序查询参数sort可以传递:new Sort(new Order(Direction.DESC, &

11、quot;personId"), new Order(Direction.ASC, "age")Direction.DESC:降序排列Direction.ASC:生序排列personId和age:列名其他方法可以进行自定义,方式参考代码范例推荐精选2.3 自定义查询支持两种模式的自定义查询:(1) 使用 Query 创建查询Query 注解的使用非常简单,只需在声明的方法上面标注该注解,同时提供一个 JP QL 查询语句即可,如下所示:Query 支持命名参数示例 public interface UserDao extends BaseDao<Accoun

12、tInfo, Long> public AccountInfo save(AccountInfo accountInfo); /与参数的顺序无关 Query("from AccountInfo a where a.accountId = :id") public AccountInfo findByAccountId(Param("id")Long accountId); /与参数的顺序相关 Query("from AccountInfo a where a.accountId = ?1") public AccountInfo

13、 findById(Long accountId); 此外,也可以通过使用 Query 来执行一个更新操作,为此,我们需要在使用 Query 的同时,用 Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询。如下所示:使用 Modifying 将查询标识为修改查询推荐精选 Modifying Query("update AccountInfo a set a.salary = ?1 where a.salary < ?2") public int increaseSalary(int after, int before); 方法中的

14、参数顺序与Query中的变量顺序保持一致。(2)通过解析方法名创建查询例1. 根据命名规则写对应的抽象方法即可.根据 username 查找 user.只需在 UserDao 中 填写如下方法. Java代码1. public List<User> findByUsername(String username);  例2. 根据两个属性查询. Java代码1. public List<User> findByUsernameAndPassword(String username,String

15、 password);框架在进行方法名解析时,会先把方法名多余的前缀截取掉,比如 find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。并且如果方法的最后一个参数是 Sort 或者 Pageable 类型,也会提取相关的信息,以便按规则进行排序或者分页查询。在创建查询时,我们通过在方法名中使用属性名称来表达,比如 findByUserAddressZip ()。框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析,详细规则如下(此处假设该方法针对的域对象为 AccountInfo 类型):· 先判断 userAddres

16、sZip (根据 POJO 规范,首字母变为小写,下同)是否为 AccountInfo 的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,继续第二步;推荐精选· 从 右往左截取第一个大写字母开头的字符串(此处为 Zip),然后检查剩下的字符串是否为 AccountInfo 的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,则重复第二步,继续从右往左截取;最后假设 user 为 AccountInfo 的一个属性;· 接 着处理剩下部分( AddressZip ),先判断 user 所对应的类型是否有 addressZip 属性,如果有,则表示该方法最

17、终是根据 "AccountInfo.user.addressZip" 的取值进行查询;否则继续按照步骤 2 的规则从右往左截取,最终表示根据 "AccountInfo.user.address.zip" 的值进行查询。可 能会存在一种特殊情况,比如 AccountInfo 包含一个 user 的属性,也有一个 userAddress 属性,此时会存在混淆。读者可以明确在属性之间加上 "_" 以显式表达意图,比如 "findByUser_AddressZip()" 或者 "findByUserAddress

18、_Zip()"。在查询时,通常需要同时根据多个属性进行查询,且查询的条件也格式各样(大于某个值、在某个范围等等),Spring Data JPA 为此提供了一些表达条件查询的关键字,大致如下:· And - 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd);· Or - 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr);· Between - 等价于 SQL 中的 b

19、etween 关键字,比如 findBySalaryBetween(int max, int min);· LessThan - 等价于 SQL 中的 "<",比如 findBySalaryLessThan(int max);· GreaterThan - 等价于 SQL 中的">",比如 findBySalaryGreaterThan(int min);· IsNull - 等价于 SQL 中的 "is null",比如 findByUsernameIsNull();· IsNot

20、Null - 等价于 SQL 中的 "is not null",比如 findByUsernameIsNotNull();· NotNull - 与 IsNotNull 等价;· Like - 等价于 SQL 中的 "like",比如 findByUsernameLike(String user);· NotLike - 等价于 SQL 中的 "not like",比如 findByUsernameNotLike(String user);推荐精选· OrderBy - 等价于 SQL 中的 &

21、quot;order by",比如 findByUsernameOrderBySalaryAsc(String user);· Not - 等价于 SQL 中的 "! =",比如 findByUsernameNot(String user);· In - 等价于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;· NotIn - 等价于 SQL 中的 &q

22、uot;not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;创建查询的顺序Spring Data JPA 在为接口创建代理对象时,如果发现同时存在多种上述情况可用,它该优先采用哪种策略呢?为此,<jpa:repositories> 提供了 query-lookup-strategy 属性,用以指定查找的顺序。它有如下三个取值:· create - 通过解析方法名字来创建查询。即使有符合的命名查询,或者方法通过

23、 Query 指定的查询语句,都将会被忽略。· create-if-not-found - 如果方法通过 Query 指定了查询语句,则使用该语句实现查询;如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;如果两者都没有找到,则通过解析方 法名字来创建查询。这是 query-lookup-strategy 属性的默认值。· use-declared-query - 如果方法通过 Query 指定了查询语句,则使用该语句实现查询;如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;如果两者都没有找到,则抛出异常。推荐精选2.4 配

24、置文件规范persistence.xml路径:classpathMETA-INFpersistence.xml内容:<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="version="2.0"><!- Name属性用于定义持久化单元的名字 (name必选,空值也合法); transaction-type(RESOURCE_LOCAL : 本地事物,针对一个数据库;JTA:全局事物,跨数据库) -><persistenc

25、e-unit name="student" transaction-type="RESOURCE_LOCAL"><class>cn.damai.student.core.domain.Course</class><class>cn.damai.student.core.domain.StudentCourse</class><class>cn.damai.student.core.domain.Student</class><class>cn.damai.stude

26、nt.core.domain.Teacher</class><class>cn.damai.student.core.domain.Department</class><!- 用于指定持久化实现厂商类 -><provider>org.hibernate.ejb.HibernatePersistence</provider><!- 配置数据库类型 mysql:"java:/MySqlDS" oradle:"java:/OracleDS" -> <jta-data-so

27、urce>java:/MySqlDS</jta-data-source> <!- 可选 -><properties><property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />推荐精选<property name="packagesToScan" value="cn.damai.student.core.domain" /><!- 配置是否自动创

28、建数据库表 create:加载时,根据实体类重新创建表结构 create-drop:加载时,根据实体类重新创建表结构,退出时,删除表结构 update:运行时根据实体类生成表结构,如果实体类和表结构不同,会更新表结构 validate:加载时验证实体类和表结构是否相同,不同报异常 -><property name="hibernate.hbm2ddl.auto" value="update" /></properties></persistence-unit></persistence>applica

29、tionContext.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="htt

30、p:/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/context http:/www.springf

31、ramework.org/schema/context/spring-context.xsd http:/www.springframework.org/schema/tx http:/www.springframework.org/schema/tx/spring-tx-2.5.xsd http:/www.springframework.org/schema/data/jpa http:/www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd"><!- spring 组件扫描 -><context

32、:component-scan base-package="cn.damai" /><!- 数据源 -><bean id="student_dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"推荐精选destroy-method="close"><property name="driverClass" value="com.mysql.jdbc.Driver" />

33、<property name="jdbcUrl" value="jdbc:mysql:/192.168.66.10:3306/new_schema" /><property name="user" value="root" /><property name="password" value="mysql" /><property name="initialPoolSize" value="2"

34、/><property name="minPoolSize" value="2" /><property name="maxPoolSize" value="50" /><property name="maxIdleTime" value="25000" /><property name="acquireIncrement" value="2" /><property name

35、="idleConnectionTestPeriod" value="60" /><property name="testConnectionOnCheckout" value="true" /><property name="testConnectionOnCheckin" value="true" /><property name="automaticTestTable" value="test_c3p0&

36、quot; /><property name="checkoutTimeout" value="5000" /></bean><!- JPA实体管理器工厂 -><bean id="student_entityManagerFactory"class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><property name="dataSource"

37、; ref="student_dataSource" /><property name="persistenceUnitName" value="student" /><property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"推荐精选 /><property name="jpaVendorAdapter"><bean cl

38、ass="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"><property name="generateDdl" value="false" /><property name="showSql" value="true" /></bean></property></bean><!- 使用annotation定义事务 -><tx:anno

39、tation-driven transaction-manager="transactionManager" /><bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="entityManagerFactory" ref="student_entityManagerFactory" /></bean>&l

40、t;!- 在服务启动时,将dao层接加入到容器管理中。CustomImpl为扩展实现类标识(如果有实现类的话) transaction-manager-ref="transactionManager"-><jpa:repositoriesbase-package="cn.damai.student.core.dao,cn.damai.student.impl.custom.dao"query-lookup-strategy="create-if-not-found" repository-impl-postfix=&quo

41、t;CustomImpl"entity-manager-factory-ref="student_entityManagerFactory"></jpa:repositories></beans>推荐精选2.5事务处理可以在业务层(Service)使用spring事务。默认情况下,Spring Data JPA 实现的方法都是使用事务的。针对查询类型的方法,其等价于 Transactional(readOnly=true);增删改类型的方法,等价于 Transactional。可以看出,除了将查询的方法设为只读事务外,其他事务属性均采

42、用默认值。如果用户觉得有必要,可以在接口方法上使用 Transactional 显式指定事务属性,该值覆盖 Spring Data JPA 提供的默认值。同时,也可以在业务层方法上使用 Transactional 指定事务属性,这主要针对一个业务层方法多次调用持久层方法的情况。持久层的事务会根据设置的事务传播行为来决定是挂起业务层事务还是加入业务层的事务。Transactional只能被应用到public方法上, 对于其它非public的方法,如果标记了Transactional也不会报错,但方法没有事务功能.Spring使用声明式事务处理,默认情况下,如果被注解的数据库操作方法中发生了unc

43、hecked异常,所有的数据库操作将rollback;如果发生的异常是checked异常,默认情况下数据库操作还是会提交的。这种默认的行为是可以改变的。使用Transactional注解的noRollbackFor和rollbackFor属性如:Transactional(rollbackFor=Exception.class)可以使checked异常发生时,数据库操作也rollback、Transactional(noRollbackFor=RuntimeException.class)可以使unchecked异常发生时也提交数据库操作。也可以使用noRollbackForClassName

44、、rollbackForClassName属性来指定一个异常类名的String数组来改变默认的行为。读取数据库中的数据时是不需要事务管理的,这种情况下可以使用事务的传播行为来告诉Spring不需要开启事务,如:Transactional(propagation = Propagation.NOT_SUPPORTED)。推荐精选事务的传播行为有:1.REQUIRED:表示业务方法需要在一个事务中处理,如果业务方法执行时已经在一个事务中,则加入该事务,否则重新开启一个事务。这也是默认的事务传播行为;2. NOT_SUPPORTED:声明业务方法不需要事务,如果业务方法执行时已经在一个事务中,则事务

45、被挂起,等方法执行完毕后,事务恢复进行;3. REQUIRES_NEW:表明业务方法需要在一个单独的事务中进行,如果业务方法进行时已经在一个事务中,则这个事务被挂起,并重新开启一个事务来执行这个业务方法,业务方法执行完毕后,原来的事务恢复进行;4. MANDATORY:该属性指定业务方法只能在一个已经存在的事务中进行,业务方法不能发起自己的事务;如果业务方法没有在一个既有的事务中进行,容器将抛出异常;5. SUPPORTS:该属性指定,如果业务方法在一个既有的事务中进行,则加入该事务;否则,业务方法将在一个没有事务的环境下进行;6. NEVER:指定业务方法不可以在事务中进行,如果业务方法执行

46、时已经在一个事务中,容器将抛出异常;7. NESTED:该属性指定,如果业务方法在一个既有的事务中执行,则该业务方法将在一个嵌套的事务中进行;否则,按照REQUEIRED来对待。它使用一 个单独的事务,这个事务可以有多个rollback点,内部事务的rollback对外部事务没有影响,但外部事务的rollback会导致内部事务的 rollback。这个行为只对DataSourceTransactionManager有效。/事务传播属性    Transactional(propagation=Propagation.REQUIRED) /如果有事务,那么加入事务,

47、没有的话新建一个(不写的情况下)    Transactional(propagation=Propagation.NOT_SUPPORTED) /容器不为这个方法开启事务    Transactional(propagation=Propagation.REQUIRES_NEW) /不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务    Transactional(propagation=Propagation.MANDATORY) /必须在一个已有的事务中执行,否则抛出

48、异常推荐精选    Transactional(propagation=Propagation.NEVER) /必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)    Transactional(propagation=Propagation.SUPPORTS) /如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.         Transactional(p

49、ropagation=Propagation.NESTED)     Transactional (propagation = Propagation.REQUIRED,readOnly=true) /readOnly=true只读,不能更新,删除     Transactional (propagation = Propagation.REQUIRED,timeout=30)/设置超时时间     Transactional (propagation = Propagation.REQUIRED,iso

50、lation=Isolation.DEFAULT)/设置数据库隔离级别用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception("注释");)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚 ,如下:Transactional(rollbackFor

51、=Exception.class) /指定回滚,遇到异常Exception时回滚    public void methodName()        throw new Exception("注释");    Transactional(noRollbackFor=Exception.class)/指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚   

52、 public ItimDaoImpl getItemDaoImpl()         throw new RuntimeException("注释");    推荐精选2.6 为接口中的部分方法提供自定义实现有些时候,可能需要在某些方法中做一些特殊的处理,此时自动生成的代理对象不能完全满足要求。为了能够为部分方法提供自定义实现,我们可以采用如下的方法:· 将需要手动实现的方法从持久层接口(假设为 PersonDao )中抽取出来,独立成一个新的接口(假设为Per

53、sonDaoCustom );· 为 PersonDaoCustom 提供自定义实现(假设为 PersonDaoCustomImpl );· 将 PersonDaoCustomImpl 配置为 Spring Bean;· 在 <jpa:repositories> 中指定实现类的后缀(比如“CustomImpl”)。 <jpa:repositories > 提供了一个 repository-impl-postfix 属性,用以指定实现类的后缀。假设做了如下配置:设置自动查找时默认的自定义实现类命名规则 <jpa:repositories base-package="cn.damai.jpa.dem

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 社会民生


经营许可证编号:宁ICP备18001539号-1