@Transactional +自定义注解不生效_SpringBoot之路(三)SpringDataJpa中常用注解的使用...

1 @Query注解详解及其用法

说明:本文的写作构建在笔者的SpringBoot之路(二)使用用Spring-Data-JPA访问数据库进行基本的CRUD操作这篇文章的基础之上。

@Query注解在spring-data-jpa中可用来定制自定义sql语句的数据库增删改查操作,使用起来也是非常方便

1.1 源码分析

@Retention(RetentionPolicy.RUNTIME)

1.2 @Query的用法

使用命名查询为实体声明查询是一种有效的方法,对于少量查询 很有效;一般只需要关心@Query里面的value和nativeQuery的值;使 用声明式JPQL查询有一个好处,就是启动的时候就知道语法正确与否。

示例:声名一个@Query注解装饰的方法在UserRepository上

(1)@Query注解中自定义select语句

@Query(value=

(2)@Query注解中自定义update语句

@Modifying

注意:update操作必须在@Query注解上方加上@Modifying注解,否则执行sql语句时会报无法提取结果集异常

1.3 like查询,注意不会自动加上%关键字

@Query(value=

注意: nativeQuery不支持直接Sort的参数查询

nativeQuery的错误写法,下面这个写法会使项目启动时报错:

@Query(value=

1.4 本节测试

以1.2中的在@Query注解中自定义update语句为例,完成Service层和Controller层代码

Service层代码

//UserService 接口中添加抽象方法

controller层代码

@PutMapping(

这时就可以通过postman测试效果了

// 请求方法与URL

从返回结果的email字段可发现用户的邮箱已经发生了改变

nativeQuery排序的正确写法

@Query(value=

使用@Query注解查询时的不足就是不支持动态条件查询

2 javax.persistence概况介绍

虽然Spring Data JPA已经帮我们对数据的操作封装得很好了, 约定大于配置思想,帮我们默认了很多东西。JPA(Java持久性API) 是存储业务实体关联的实体来源。它显示了如何定义一个面向普通 Java对象(POJO)作为一个实体,以及如何与管理关系实体提供一套 标准。因此,javax.persistence下面的有些注解还是必须要去了解的,以便于更好地提高工作效率.

(1)javax.persistence位于org.hibernate:hibernate-core.jar包里面,可 以通过Intellij Idea的maven插件直接分析一下maven的依赖,也可以用 $ mvn dependency:tree分析,例如:

[INFO] |  +- org.hibernate:hibernate-core:jar:5.3.9.Final:compile
[INFO] | | +- javax.persistence:javax.persistence-api:jar:2.2:compile
[INFO] | | +- org.javassist:javassist:jar:3.23.1-GA:compile
[INFO] | | +- antlr:antlr:jar:2.7.7:compile
[INFO] | | +- org.jboss:jandex:jar:2.0.5.Final:compile
[INFO] | | +- org.dom4j:dom4j:jar:2.1.1:compile
[INFO] | | \- org.hibernate.common:hibernate-commons-annotations:jar:5.0.4.Final:compile
[INFO] | +- org.springframework.data:spring-data-jpa:jar:2.1.6.RELEASE:compile
[INFO] | | +- org.springframework.data:spring-data-commons:jar:2.1.6.RELEASE:compile
[INFO] | | +- org.springframework:spring-orm:jar:5.1.6.RELEASE:compile
[INFO] | | \- org.springframework:spring-tx:jar:5.1.6.RELEASE:compile
[INFO] | \- org.springframework:spring-aspects:jar:5.1.6.RELEASE:compile

(2)通过Intellij Idea的Diagram来看一下此模块类的关键关 系,如图所示:@Transactional +自定义注解不生效_SpringBoot之路(三)SpringDataJpa中常用注解的使用..._第1张图片

(3)下图显示了JPA的类的层次结构,包括核心类和JPA接口。@Transactional +自定义注解不生效_SpringBoot之路(三)SpringDataJpa中常用注解的使用..._第2张图片

(4)JPA类层次结构的显示单元

单元 描述
EntityManagerFactory 一个EntityManager的工厂类,创建并管理多个EntityManager实例
EntityManager 一个接口,管理持久化操作对象,工作原理类似工厂的查询实例
Entity 实体是持久性对象,是存储在数据库中的记录
EntityTransaction 与EntityManager是一对一的关系,对于每个EntityManager,操作是由EntityTransaction来维护的
Persistence 这个类包含使用静态方法获取EntityManagerFactory的实例
Query 该接口由每个JPA供应商实现,能够获得符合标准的关系对象

上述的类和接口用于存储实体到数据库的一个记录,帮助程序员 通过减少自己编写的代码将数据存储到数据库中,使他们能够专注于 更重要的业务活动代码,如数据库表映射的类编写代码。

3 javax.persistence包下的基本注解

javax.persistence包下基本注解包括@Entity、@Table、@Id、@IdClass、 @GeneratedValue、@Basic、@Transient、@Column、@Temporal、 @Enumerated、@Lob。

3.1 @Entity

先看一个Blog的示例,其中实体的配置如下:

@Entity

在数据库中新建一张与UserBlogEntity实体类对应的表:

use mysql;

@Entity定义对象将会成为被JPA管理的实体,将映射到指定的数据库表。

200),

@Entity定义对象将会成为被JPA管理的实体,将映射到指定的数 据库表。

public 

3.2  @Table

@Table指定数据库的表名

public @interface Table {
//表名,可选,不填写时默认为实体类名
String name() default "";
//表的catalog
String catalog() default "";
//表所在的schema
String schema() default "";
//唯一约束,只有在创建表时有用,默认不需要
UniqueConstraint[] uniqueConstraints() default {};
//索引,只在创建表时有用,默认不需要
Index[] indexes() default {};
}

3.3 @Id

@Id定义属性为数据库的主键,一个实体里面必须有一个

3.4 @IdClass

@IdClass利用外部类的联合主键

public 
  • 作为符合主键类,要满足以下几点要求。

  • 必须实现Serializable接口。

  • 必须有默认的public无参数的构造方法。

  • 必须覆盖equals和hashCode方法。equals方法用于判断两个对 象是否相同,EntityManger通过find方法来查找Entity时是根 据equals的返回值来判断的。在本例中,只有对象的name和 email值完全相同或同一个对象时才返回true,否则返回 false。hashCode方法返回当前对象的哈希码,生成的hashCode相同的概率越小越好,算法可以进行优化。

用法:假设UserBlog的联合主键是createUserId和title,新增一个UserBlogKey的类,UserBlogkey.class代码如下:

@NoArgsConstructor

UserBlogRepository中的改动如下:

public 

@IdClass的用法实战

(1)先写两个往User_Blog表中插入数据的接口和一个根据Id查询UserBlogEntity的接口

service层代码 UserBlogService.java

public 

UserBlogServiceImpl.java

@Service

controller层代码 UserBlogController.java

@RestController

postman测试

(1) 插入一条数据

//请求方法与URL

(2)批量插入多条数据

//请求方法与URL

(3) 使用联合主键查询单条记录

//请求方法与URL

3.5 @GeneratedValue

@GeneratedValue为主键生成策略,例如:

public 

GenerationType一共有以下4个值:

public 

3.6 @Basic@Basic表示属性是到数据库表的字段的映射。如果实体的字段上 没有任何注解,默认即为@Basic。

public 

3.7 @Transient

@Transient表示该属性并非一个到数据库表的字段的映射,表示 非持久化属性;

与@Basic作用相反。JPA映射数据库的时候忽略它。

3.8 @Column

@Column定义该属性对应数据库中的列名

public 

3.9 @Temporal

@Temporal用来设置Date类型的属性映射到对应精度的字段。

(1)@Temporal(TemporalType.DATE)映射为日期∥date(只有 日期)

(2)@Temporal(TemporalType.TIME)映射为日期∥time(只有 时间)

(3)@Temporal(TemporalType.TIMESTAMP)映射为日期∥date time(日期+时间)

3.10 @Enumerated

@Enumerated很好用,直接映射enum枚举类型的字段。

(1) 看源码:

public 

(2) 用法:

public 

这时插入两条数据,数据库里面的值是MAIL/FMAIL,而不是“男 性”/“女性”。如果我们用@Enumerated(EnumType.ORDINAL),那么 这时数据库里面的值是0,1。但是实际工作中,不建议用数字下标,

因为枚举里面的属性值是会不断新增的,如果新增一个,位置变化了 就惨了。

3.11 @Lob

@Lob 将属性映射成数据库支持的大对象类型,支持以下两种数 据库类型的字段。

(1)Clob(Character Large Ojects)类型是长字符串类型, java.sql.Clob、Character[]、char[]和String将被映射为Clob类 型

(2)Blob(Binary Large Objects)类型是字节类型, java.sql.Blob、Byte[]、byte[]和实现了Serializable接口的类型 将被映射为Blob类型。

(3)Clob、Blob占用内存空间较大,一般配合 @Basic(fetch=FetchType.LAZY)将其设置为延迟加载。

小结

本文主要结合源码和测试用例系统地讲解了spring-data-jpa中@Query注解及javax.persistence包下的基本注解及其用法和需要注意的坑,限于文章篇幅,关于联表查询的注解及其使用和JpoRepository扩展详解及高级查询用法将放在下一遍文章中完成。

推荐阅读

SpringBoot之路(二)使用用Spring-Data-JPA访问数据库进行基本的CRUD操作

参考文档

:张振华著《Spring Data Jpa从入门到精通》第4章和第5章部分

欢迎新读者扫描下方二维码关注笔者的微信公众号@Transactional +自定义注解不生效_SpringBoot之路(三)SpringDataJpa中常用注解的使用..._第3张图片

需要源码的读者在公众号中发送消息“bootDemo项目源码”即可获取该项目源码地址

你可能感兴趣的:(@Transactional,+自定义注解不生效)