本章小宋讲一下Spring Data Jpa的一些常用注解和一些简单的基础操作。

目录

  • JPA注解和简单操作
    • 1.相关依赖
    • 2.配置数据库连接信息和JPA配置
    • 3.实体类
      • 3.1 创建表
      • 3.2 创建主键
      • 3.3 设置字段类型
      • 3.4 指定不持久化特定字段
      • 3.5 声明大字段
      • 3.6 创建枚举类型的字段
    • 4.创建操作数据库的 Repository 接口
      • 4.1 JPA自带方法用例
        • 4.1.1 增删改查
        • 4.1.2 条件查询
      • 4.2 JPA自定义Sql语句
      • 4.3 创建异步方法
    • 5.测试

JPA注解和简单操作

这里小宋讲解一下Spring Data Jpa的相关知识。

1.相关依赖

 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

2.配置数据库连接信息和JPA配置

下面的配置中要先去单独说一下 spring.jpa.hibernate.ddl-auto=create这个配置选项。
该属性常用的选项包含4种:

  1. create:每次重新启动项目都会重新创建新表结构,会导致数据丢失
  2. create-drop:每次启动项目创建表结构,关闭项目删除表结构
  3. update:每次启动项目会更新表结构
  4. validate:验证表结构,不对数据库进行任何更改

一定要不要在生产环境使用 ddl 自动生成表结构,一般推荐手写 SQL 语句配合 Flyway 来做这些事情。

spring.datasource.url=jdbc:mysql://localhost:3306/springboot_jpa?useSSL=false&serverTimezone=CTT
spring.datasource.username=root
spring.datasource.password=123456
# 打印出 sql 语句
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.open-in-view=false
# 创建的表的 ENGINE 为 InnoDB
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL55Dialect

3.实体类

我们为这个类添加 @Entity 注解代表它是数据库持久化类,并配置主键 id。

import lombok.Data;
import lombok.NoArgsConstructor;import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity
@Data
@NoArgsConstructor
publicclass Person {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(unique = true)private String name;private Integer age;public Person(String name, Integer age) {this.name = name;this.age = age;}}

3.1 创建表

@Entity:声明一个类对应一个数据库实体。
@Table:设置表名
@NoArgsConstructor:无参构造方法

@Entity
@Data
@NoArgsConstructor
publicclass Person {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(unique = true)private String name;private Integer age;public Person(String name, Integer age) {this.name = name;this.age = age;}

3.2 创建主键

@Id:声明一个字段为主键。

使用@Id声明之后,我们还需要定义主键的生成策略。我们可以使用 @GeneratedValue 指定主键生成策略。

1.通过 @GeneratedValue直接使用 JPA 内置提供的四种主键生成策略来指定主键生成策略。

    @Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;

JPA使用枚举定义了4种常见的主键生成策略:

public enum GenerationType {/*** 使用一个特定的数据库表格来保存主键* 持久化引擎通过关系数据库的一张特定的表格来生成主键,*/TABLE,/***在某些数据库中,不支持主键自增长,比如Oracle、PostgreSQL其提供了一种叫做"序列(sequence)"的机制生成主键*/SEQUENCE,/*** 主键自增长*/IDENTITY,/***把主键生成策略交给持久化引擎(persistence engine),*持久化引擎会根据数据库在以上三种主键生成 策略中选择其中一种*/AUTO
}

@GeneratedValue注解默认使用的策略是GenerationType.AUTO

public @interface GeneratedValue {GenerationType strategy() default AUTO;String generator() default "";
}

一般使用 MySQL 数据库的话,使用GenerationType.IDENTITY策略比较普遍一点(分布式系统的话需要另外考虑使用分布式 ID)。
2.通过 @GenericGenerator声明一个主键策略,然后 @GeneratedValue使用这个策略

@Id
@GeneratedValue(generator = "IdentityIdGenerator")
@GenericGenerator(name = "IdentityIdGenerator", strategy = "identity")
private Long id;

等同于:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

jpa 提供的主键生成策略有如下一些:

public class DefaultIdentifierGeneratorFactoryimplements MutableIdentifierGeneratorFactory, Serializable, ServiceRegistryAwareService {@SuppressWarnings("deprecation")public DefaultIdentifierGeneratorFactory() {register( "uuid2", UUIDGenerator.class );register( "guid", GUIDGenerator.class );            // can be done with UUIDGenerator + strategyregister( "uuid", UUIDHexGenerator.class );            // "deprecated" for new useregister( "uuid.hex", UUIDHexGenerator.class );     // uuid.hex is deprecatedregister( "assigned", Assigned.class );register( "identity", IdentityGenerator.class );register( "select", SelectGenerator.class );register( "sequence", SequenceStyleGenerator.class );register( "seqhilo", SequenceHiLoGenerator.class );register( "increment", IncrementGenerator.class );register( "foreign", ForeignGenerator.class );register( "sequence-identity", SequenceIdentityGenerator.class );register( "enhanced-sequence", SequenceStyleGenerator.class );register( "enhanced-table", TableGenerator.class );}public void register(String strategy, Class generatorClass) {LOG.debugf( "Registering IdentifierGenerator strategy [%s] -> [%s]", strategy, generatorClass.getName() );final Class previous = generatorStrategyToClassNameMap.put( strategy, generatorClass );if ( previous != null ) {LOG.debugf( "    - overriding [%s]", previous.getName() );}}}

3.3 设置字段类型

@Column:声明字段。

示例:
设置属性 userName 对应的数据库字段名为 user_name,长度为 32,非空

@Column(name = "user_name", nullable = false, length=32)
private String userName;

设置字段类型并且加默认值,这个还是挺常用的。

@Column(columnDefinition = "tinyint(1) default 1")
private Boolean enabled;

3.4 指定不持久化特定字段

@Transient :声明不需要与数据库映射的字段,在保存的时候不需要保存进数据库 。

如果我们想让secrect 这个字段不被持久化,可以使用 @Transient关键字声明。

@Entity(name="USER")
public class User {......@Transientprivate String secrect; // not persistent because of @Transient}

除了 @Transient关键字声明, 还可以采用下面3种方法:

static String secrect; // not persistent because of static
final String secrect = “Satish”; // not persistent because of final
transient String secrect; // not persistent because of transient

但是一般注解的方式使用的比较多

3.5 声明大字段

@Lob:声明某个字段为大字段。

@Lob
private String content;
@Lob
//指定 Lob 类型数据的获取策略, FetchType.EAGER 表示非延迟 加载,而 FetchType. LAZY 表示延迟加载 ;
@Basic(fetch = FetchType.EAGER)
//columnDefinition 属性指定数据表对应的 Lob 字段类型
@Column(name = "content", columnDefinition = "LONGTEXT NOT NULL")
private String content;

3.6 创建枚举类型的字段

public enum Gender {MALE("男性"),FEMALE("女性");private String value;Gender(String str){value=str;}
}

可以通过@Enumerated注解去使用枚举类型的字段

@Entity
@Table(name = "role")
public class Role {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String description;@Enumerated(EnumType.STRING)private Gender gender;省略getter/setter......
}

数据库里面对应存储的是 MAIL/FEMAIL。

如何验证我们已经成功,运行项目后,查看控制台是否打印出创建表的 sql 语句,并且数据库中表真的被创建出来的话,说明你成功了。

控制台打印出来的 sql 语句类似下面这样:

droptableifexists person
CREATETABLE`person` (`id`bigint(20) NOTNULL AUTO_INCREMENT,`age`int(11) DEFAULTNULL,`name`varchar(255) DEFAULTNULL,PRIMARY KEY (`id`)
) ENGINE=InnoDBDEFAULTCHARSET=utf8;
altertable person addconstraint UK_p0wr4vfyr2lyifm8avi67mqw5 unique (name)

4.创建操作数据库的 Repository 接口

@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
}

首先这个接口加了 @Repository 注解,代表它和数据库操作有关。另外,它继承了 JpaRepository<Person, Long>接口,而JpaRepository<Person, Long>源码如下:

@NoRepositoryBean
publicinterface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {List<T> findAll();List<T> findAll(Sort var1);List<T> findAllById(Iterable<ID> var1);<S extends T> List<S> saveAll(Iterable<S> var1);void flush();<S extends T> S saveAndFlush(S var1);void deleteInBatch(Iterable<T> var1);void deleteAllInBatch();T getOne(ID var1);<S extends T> List<S> findAll(Example<S> var1);<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

所以当我们继承了JpaRepository<T, ID> ,也就可以去调用 JPA 为我们提供好的增删改查、分页查询以及根据条件查询等方法。

4.1 JPA自带方法用例

4.1.1 增删改查

  1. 增(保存用户到数据库)
    Person person = new Person("SnailClimb", 23);personRepository.save(person);
save()方法对应 sql 语句是: insert into person (age, name) values (23,"snailclimb")
  1. 查(根据id查找用户)
 Optional<Person> personOptional = personRepository.findById(id);
findById()方法对应 sql 语句就是:select * from person p where p.id = id
  1. 删(根据id删除用户)
  personRepository.deleteById(id);
deleteById()方法对应 sql 语句就是:delete from person where id=id
  1. 改(根据id更新用户信息)

更新操作也是通过save()方法实现。

     Person person = new Person("SnailClimb", 23);Person savedPerson = personRepository.save(person);// 更新 person 对象的姓名savedPerson.setName("UpdatedName");personRepository.save(savedPerson);

这里是先新增再去更新,也可以先查出一个用户的信息再去更新。

这里最后的save()方法相当于 sql 语句:update person set name="UpdatedName" where id=id

4.1.2 条件查询

下面这些方法是根据 JPA 提供的语法自定义的,你需要将下面这些方法写到 PersonRepository 中。

假如我们想要根据 Name 来查找 Person ,你可以这样:

Optional<Person> findByName(String name);

如果你想要找到年龄大于某个值的人,你可以这样:

List<Person> findByAgeGreaterThan(int age);

4.2 JPA自定义Sql语句

很多时候我们自定义 sql 语句会非常有用。

根据 name 来查找 Person:

@Query("select p from Person p where p.name = :name")
Optional<Person> findByNameCustomeQuery(@Param("name") String name);

Person 部分属性查询,避免 select *操作:

@Query("select p.name from Person p where p.id = :id")
String findPersonNameById(@Param("id") Long id);

根据 id 更新Person name:

@Modifying
@Transactional
@Query("update Person p set p.name = ?1 where p.id = ?2")
void updatePersonNameById(String name, Long id);

根据 id 删除Person name:

@Modifying
@Transactional
@Query("delete from Person where id = ?1")
void deletePersonNameById(Long id);

4.3 创建异步方法

如果我们需要创建异步方法的话,也比较方便。

异步方法在调用时立即返回,然后会被提交给TaskExecutor执行。当然你也可以选择得出结果后才返回给客户端。

@Async
Future<User> findByName(String name);@Async
CompletableFuture<User> findByName(String name);

5.测试

@SpringBootTest
@RunWith(SpringRunner.class)
publicclass PersonRepositoryTest {@Autowiredprivate PersonRepository personRepository;private Long id;/*** 保存person到数据库*/@Beforepublic void setUp() {assertNotNull(personRepository);Person person = new Person("SnailClimb", 23);Person savedPerson = personRepository.saveAndFlush(person);// 更新 person 对象的姓名savedPerson.setName("UpdatedName");personRepository.save(savedPerson);id = savedPerson.getId();}/*** 使用 JPA 自带的方法查找 person*/@Testpublic void should_get_person() {Optional<Person> personOptional = personRepository.findById(id);assertTrue(personOptional.isPresent());assertEquals("SnailClimb", personOptional.get().getName());assertEquals(Integer.valueOf(23), personOptional.get().getAge());List<Person> personList = personRepository.findByAgeGreaterThan(18);assertEquals(1, personList.size());// 清空数据库personRepository.deleteAll();}/*** 自定义 query sql 查询语句查找 person*/@Testpublic void should_get_person_use_custom_query() {// 查找所有字段Optional<Person> personOptional = personRepository.findByNameCustomeQuery("SnailClimb");assertTrue(personOptional.isPresent());assertEquals(Integer.valueOf(23), personOptional.get().getAge());// 查找部分字段String personName = personRepository.findPersonNameById(id);assertEquals("SnailClimb", personName);System.out.println(id);// 更新personRepository.updatePersonNameById("UpdatedName", id);Optional<Person> updatedName = personRepository.findByNameCustomeQuery("UpdatedName");assertTrue(updatedName.isPresent());// 清空数据库personRepository.deleteAll();}}

讲到这里本章对Spring Data Jpa注解和基础操作知识讲解也就结束了,如果想了解更多知识可以在对应的专栏中看系列文章,谢谢大家的观看,希望能给各位同学带来帮助。如果觉得博主写的还可以的,可以点赞收藏。

桃花岛--SpringBoot系列之Spring Data Jpa注解和基础操作相关推荐

  1. SpringBoot系列之Spring Data MongoDB教程

    SpringBoot系列之Spring Data MongoDB教程 1.MongoDB下载安装 因为没有买linux服务器,所以本博客只安装window来学习,可以点击官网下载链接进行下载,安装过程 ...

  2. ORM框架之Spring Data JPA(二)spring data jpa方式的基础增删改查

    上一篇主要在介绍hibernate实现jpa规范,如何实现数据增删改查,这一篇将会着重spring data jpa 一.Spring Data JPA 1.1 Spring Data JPA介绍: ...

  3. 使用H2Database+Druid连接池+Spring Data JPA+Ehcache实现CRUD操作

    前言 注:本篇为纯实践篇,主要用于技术整合,介绍如何搭建一个完整全面的Web项目.如果对于技术原理还不了解的童鞋可点击下方链接,学习后在来~ H2数据库教程:H2数据库入门 缓存使用教程:在Sprin ...

  4. spring-boot (三) spring data jpa

    学习文章来自:http://www.ityouknow.com/spring-boot.html spring data jpa介绍 首先了解JPA是什么? JPA(Java Persistence ...

  5. Spring Security+Spring Data Jpa 强强联手,安全管理只有更简单!

    Spring Security+Spring Data Jpa 强强联手,安全管理没有简单,只有更简单! 这周忙着更新 OAuth2,Spring Security 也抽空来一篇. Spring Se ...

  6. Spring Data JPA(官方文档翻译)

    关于本书 介绍 关于这本指南 第一章 前言 第二章 新增及注意点 第三章 项目依赖 第四章 使用Spring Data Repositories 4.1 核心概念 4.2 查询方法 4.3 定义rep ...

  7. Springboot 系列(十)使用 Spring data jpa 访问数据库

    前言 Springboot data jpa 和 Spring jdbc 同属于 Spring开源组织,在 Spring jdbc 之后又开发了持久层框架,很明显 Spring data jpa 相对 ...

  8. springboot整合hibernate_峰哥说技术系列-17 .Spring Boot 整合 Spring Data JPA

    今日份主题 Spring Boot 整合 Spring Data JPA JPA(Java Persistence API)是用于对象持久化的 API,是Java EE 5.0 平台标准的 ORM 规 ...

  9. SpringBoot 实战 (八) | 使用 Spring Data JPA 访问 Mysql 数据库

    微信公众号:一个优秀的废人 如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 如题,今天介绍 Spring Data JPA 的使用. 什么是 Spring Data JPA 在介绍 Spri ...

  10. springboot jpa sql打印_SpringBoot集成Spring Data JPA以及读写分离

    相关代码:github OSCchina JPA是什么 JPA(Java Persistence API)是Sun官方提出的Java持久化规范,它为Java开发人员提供了一种对象/关联映射工具 来管理 ...

最新文章

  1. React系列---Redux高阶运用
  2. ecplise 使用 git
  3. java中 有没有方法将浏览器标签栏去掉_用JS去掉IE窗口的标题栏,工具栏,地址栏...
  4. vb子程序未定义怎么改怎么办_vb中子程序或者函数未定义!求教解决方案,
  5. requests与bs4编码
  6. python动态图形_利用matplotlib实现根据实时数据动态更新图形
  7. python爬虫使用代理ip_爬虫使用代理IP的为什么不能全部成功
  8. 二叉树:你真的会翻转二叉树么?
  9. fork函数_Linux中子进程回收函数:wait和waitpid
  10. 算法导论 资源 课后答案 PDF
  11. 51单片机驱动TM1638芯片+Proteus仿真
  12. FastReport报表控件使用技巧总结
  13. 七大江河水系--黄河(二)
  14. java并发三大特性--有序性、可见性、原子性
  15. php fileinfo 作用,PHP Fileinfo函数 详解
  16. LightSwitch 社区内容汇总 – 2012年9月
  17. AndroidStudio运行app,会装上多个app
  18. java语言for模板_Java中使用FreeMaker实现模板渲染
  19. 名悦集团:为什么司机建议买车尽量买便宜的
  20. 既然硕士毕业也去搞开发,那还去读研值吗?

热门文章

  1. MAC中SPSS无法打开数据
  2. 深入理解CatBoost
  3. 通过倍福Twincat的R3IO添加外部C++程序
  4. vue build打包后提示:Tip: built files are meant to be served over an HTTP server
  5. python计算无穷级数求和_[探求无穷级数求和的几种常用方法]无穷级数求和常用公式...
  6. 使用Java写入Excel下拉选择框选项过多不显示问题
  7. redis读缓存超时故障处理
  8. 安卓 控件靠右对齐_LinearLayout中组件右对齐
  9. linux添加字体库
  10. 算法题:矩阵修改为黑白矩阵