@[toc]
前言:之前一直用的都是Mybatis,最近由于工作原因,要使用JPA,因此整理一下学习笔记防止忘记,也希望能够帮到需要使用这个技术的人
Hibernate
的一个抽象,从功能上来说是 Hibernate 的一个子集 nosql(redis,mongoDB)
和关系型数据库( jdbc,jpa
)存储 JPA,MySQL,Web
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <version>5.1.28</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> 复制代码
application.properties
文件中 # 配置数据库连接池及数据库驱动 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.mysql.jdbc.Driver # 配置mysql的链接信息 spring.datasource.username=root spring.datasource.password=root spring.datasource.url=jdbc:mysql://localhost:3306/jpaDemo?useUnicode=true&characterEncoding=utf-8 #jpa spring.jpa.database=mysql spring.jpa.database-platform=mysql #是否自动生成dd spring.jpa.generate-ddl=true # 生成方式 update 运行时在数据库生成表,若有更新则去更新数据 spring.jpa.hibernate.ddl-auto=update # 格式化sql语句 spring.jpa.properties.hibernate-format_sql=true # 控制台展示 JPA 框架生成的sql语句 spring.jpa.show-sql=true # 解决 hibernate multiple merge 问题 spring.jpa.properties.hibernate.event.merge.entity_copy_observer = allow # 使用JPA 创建表时,默认使用的存储引擎是MyISAM,通过指定数据库版本,可以使用InnoDB spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect 复制代码
package com.bisnow.demo.pojo; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String bookname; private String author; get + set + toString } 复制代码
需要一个接口继承JpaRepository<实体类名,id类型>,在接口中有现成的方法或者自定义方法
package com.bisnow.demo.repository; import com.bisnow.demo.pojo.Book; import org.springframework.data.jpa.repository.JpaRepository; public interface BookRepository extends JpaRepository<Book,Integer> { } 复制代码
@RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Autowired BookRepository bookRepository; @Test public void test1(){ List<Book> books = bookRepository.findAll(); books.forEach(b-> System.out.println(b)); } } 复制代码
JPA项目运行的时候会根据实体类自动的去数据库建表
表示这是一个实体类,默认情况下,类名就是表名
与 @Entity
并列使用,自定义数据库表名
标注主键
strategy IDENTITY AUTO SEQUENCE TABLE
package com.bisnow.demo.pojo; import javax.persistence.*; @Entity @Table(name = "t_person") public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; private Integer age; get + set 方法 } 复制代码
@GeneratedValue
策略,则 @GeneratedValue(strategy = GenerationType.IDENTITY) 复制代码
用来描述实体属性对应数据表字段,其中 name、nullable、unique、length
属性用的较多,分别用来描述字段名、字段是否可以null、字段是否唯一、字段的长度,实际开发中需要用其他属性时,可从参考文献获取api文档地址,查阅文档配置。
@Column(length = 400,name = "p_name",nullable = false,unique = true) private String name; 复制代码
此时建表能看到
在数据库中建表的时候忽略该属性
@Transient private String name; 复制代码
两个实体一对一关系,例如人和身份证就是一对一的关系
查询包含关联属性的实体对象时,能同步从数据库中获取关联的实体对象,反过来不行
package com.bisnow.demo.pojo; import javax.persistence.*; @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; @OneToOne //关联的字段 name属性可以标注表中字段的值 @JoinColumn(name = "card_id") private Card card; get + set + toString ... } 复制代码
package com.bisnow.demo.pojo; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Card { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String num; get + set + toString ... } 复制代码
@Autowired PersonRepository personRepository; @Autowired CardRepository cardRepository; @Test public void contextLoads() { Optional<Person> person = personRepository.findById(1); Person p = person.get(); System.out.println(p); Optional<Card> card = cardRepository.findById(1); Card c = card.get(); System.out.println(c); } 复制代码
两实体一对多关系,例如人和电话就是一对多关系,一个人可以有多个电话,一个电话只能属于一个人
package com.bisnow.demo.pojo; import javax.persistence.*; @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; get + set + toString ... } package com.bisnow.demo.pojo; import javax.persistence.*; @Entity public class Phone { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private Integer number; @ManyToOne @JoinColumn(name = "person_id") private Person person; get + set + toString ... } 复制代码
@Autowired PersonRepository personRepository; @Autowired PhoneRepository phoneRepository; @Test public void test2(){ List<Person> all = personRepository.findAll(); all.forEach(p-> System.out.println(p)); List<Phone> all1 = phoneRepository.findAll(); all1.forEach(p-> System.out.println(p)); } 复制代码
package com.bisnow.demo.pojo; import javax.persistence.*; @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; @OneToMany(cascade = CascadeType.MERGE,fetch = FetchType.EAGER) @JoinColumn(name = "phone_id") private List<Phone> phone; get + set + toString ... } package com.bisnow.demo.pojo; import javax.persistence.*; @Entity public class Phone { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private Integer number; get + set + toString ... } 复制代码
@Autowired PersonRepository personRepository; @Autowired PhoneRepository phoneRepository; @Test public void test2(){ List<Person> all = personRepository.findAll(); all.forEach(p-> System.out.println(p)); List<Phone> all1 = phoneRepository.findAll(); all1.forEach(p-> System.out.println(p)); } 复制代码
EAGER LAZY
CascadeType.PERSIST CascadeType.REMOVE CascadeType.DETACH CascadeType.MERGE CascadeType.REFRESH CascadeType.ALL
多对多的实体关系,例如学生和所选课程的关系,一个学生可以选多个课程,一个课程可被多个学生选择
@Entity public class Student { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; @ManyToMany(targetEntity = Course.class,fetch = FetchType.EAGER) private List<Course> courses; get + set + toString ... } @Entity public class Course { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; get + set + toString } 复制代码
@Autowired StudentRepository studentRepository; @Autowired CourseRepository courseRepository; @Test public void test3(){ List<Student> all = studentRepository.findAll(); System.out.println(all); List<Course> all1 = courseRepository.findAll(); System.out.println(all1); } 复制代码
需要一个接口继承 JpaRepository<实体类名,id类型>
,可在接口中写现有方法或者自定义的方法
public interface BookRepository extends JpaRepository<Book,Integer> { List<Book> getBookByBooknameContains(String bookname); List<Book> getBookByIdGreaterThanAndAuthorEndsWith(Integer id,String author); //表示自定义的 dml 操作方法 @Query(value = "select * from book where id = (select max(id) from book)",nativeQuery = true) Book getMaxIdBook(); // 两种传参方式 使用 ?1 的方式不需要 @Param 注解 // @Query(value = "select * from book where id > ?1",nativeQuery = true) @Query(value = "select * from book where id > :id",nativeQuery = true) List<Book> idGreaterThan(@Param("id") Integer id); //自定义 ddl 操作方法 需要 @Modifying 注解,告知此操作会对数据库的数据进行修改 // 对数据库的数据进行修改时 需要添加事务管理@Transactional(一般加在Service层) @Query(value = "update t_book set bookname = ?1 where id = ?2",nativeQuery = true) @Modifying int updateBookById(String bookname,Long id); } 复制代码
@Autowired BookRepository bookRepository; @Test public void test4(){ List<Book> b = bookRepository.getBookByBooknameContains("拾"); System.out.println(b); List<Book> b2 = bookRepository.getBookByIdGreaterThanAndAuthorEndsWith(2, "夏达"); System.out.println(b2); Book maxIdBook = bookRepository.getMaxIdBook(); System.out.println(maxIdBook); List<Book> books = bookRepository.idGreaterThan(2); System.out.println(books); } 复制代码
@Query
自定义 dml 和 ddl 方法 @Modifying
注解,并且在操作时需要添加事务管理 @Transactional
(一般加在Service层)` @Service @Transactional public class BookService { } 复制代码