SpringBoot 2.x 数据库访问中间件Spring Data JPA
ORM框架
对象关系映射(Object Relational Mapping),用于实现面向对象编程语言里不同类型系统的数据之间的转换。
即,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象和关系数据库相互映射;
异构性:
ORM可以解决数据库与程序间的异构性。例如java中使用String表示字符串,而Oracle使用varchar2,Mysql使用varchar,SQLServer使用nvarchar。
映射:
ORM提供了实现持久层的另一种模式,采用映射元数据xml来描述对象-关系的映射细节,使得ORM中间件能在任何一个java应用的业务逻辑层和数据库之间充当桥梁。
常用ORM框架
Hibernate: 全自动的框架,强大,复杂,笨重,学习成本高
Mybatis :半自动的框架(懂数据库的人才能操作)必须要自己写sql
JPA: Java Persistence API,java自带框架
本文主要讲的是使用SpringBoot集成SpringDataJPA
SpringBoot集成 SpringData JPA
SpringData官网介绍 https://spring.io/projects/spring-data
简单介绍:
image.pngSpringData特点
1.支持对象关系映射
具备ORM框架的对象关系映射功能
- 统一Repository接口
Repository<T, ID extends Serializable>
CrudRepository<T, ID extends Serializable> 基本的CRUD操作
PagingAndSortingRepository<T, ID extends Serializable> 基本CRUD分页
3.统一数据访问模板类 XXXTemplre
MongoTemplate,RedisTemplate等
JPA简介
JPA(Java Persistence API) 是Sun公司官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据。主要是为简化现有的持久化开发工作和整合ORM技术。
JPA是在吸收现有的Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。
注意:JPA是一套规范,不是一套产品。
SpringData 与JPA 的关系
image.pngimage.png
image.png
SpringData JPA 快速入门
1 .pom.xml 导入依赖
<!--springdata jpa-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!---mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2 .application.properties 配置SpringDataJPA
#配置数据库
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123
#支持sql输出
spring.jpa.show-sql=true
#format 一下 sql 进行输出
spring.jpa.properties.hibernate.format_sql=true
#自动生成开启,让表数据会自动跟随entity类的变化而变化
spring.jpa.hibernate.ddl-auto=update
#jpa对应的数据库类型
spring.jpa.database=mysql
3 . 实体类,自动对应数据库表
@Data
//该类是实体
@Entity
//对应表名
@Table(name = "user")
public class User {
//主键
@Id
//自增长主键
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/*
//主键
@Id
//用uuid生成主键
@GenericGenerator(name = "myuuid",strategy = "uuid")
@GeneratedValue(generator = "myuuid")
private Integer id;*/
//name对应数据库字段;unique=ture值唯一
@Column(name = "t_username",nullable = false,unique = true)
private String username;
@Column
private String password;
}
4 .映射接口UserRepository
/**
* 实体类,主键类型
* JpaRepository<TUser,Integer>
*/
public interface UserRepository extends JpaRepository<TUser,Integer> {
//模糊查找,命名会自动提示,按提示写,jpa会自动实现
User findUserByUsernameLike(String username);
}
5 .Controller
@RestController
public class UserController {
@Resource
UserRepository userRepository;
@GetMapping("/user/id/{id}")
public Object findById(@PathVariable int id){
// userRepository.findById(id).get() 为空的话会报500错误
return userRepository.findById(id);
}
@GetMapping("/user")
public User saveUser(User user){
return userRepository.save(user);
}
//模糊查找
@GetMapping("/user/username/{username}")
public User saveUser(@PathVariable String username){
return userRepository.findUserByUsernameLike("%"+username+"%");
}
}
JPA 单表sql 操作--关键字拼凑
JpaRepository<T,ID>,自动提示
image.png
关键字拼凑 案例
@Data //getter,setter,equals,hashcode,tostring
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
@Table(name = "person")
public class Person {
@Id
@GenericGenerator(name = "myuuid",strategy = "uuid")
@GeneratedValue(generator = "myuuid")
private String pid;
@Column(unique = true)
private String pname;
@Column
private String psex;
@Column
private Integer age;
@Column
private boolean getmarried;
}
PersonRepository
/**
* sql 关键字 拼凑
* 接口的名字必须按提示命名,除非自己实现
*/
public interface PersonRepository extends JpaRepository<Person,String> {
//查询年龄小于等于20的人
List<Person> findAllByAgeIsLessThanEqual(Integer age);
//查询年龄在20-22岁之间,并且性别是男的人
List<Person> findAllByAgeBetweenAndPsexEquals(Integer lowage,Integer highage,String sex);
//查询已结婚并且性别是男的人
List<Person> findAllByGetmarriedIsTrueAndPsexEquals(String sex);
}
关键字拼凑无法解决问题
1.实体类的属性名与表的字段名无法映射,导致关键字找不到
2.CRUD操作方式比较另类或者是你不想用的关键字的写法
3.涉及多表操作
关键字注解手写sql语句
1.使用sql语句来写sql
2.使用HQL语句来写sql
手写sql
1.如果是 删改 操作,需要加上 @Modifying 和 @Transactioinal 注解
2.如果是 SQL 语句,请在 @Query 注解上加上 NativeQuery=true 的属性
3.传参的方式有2种:
1.使用 ? 数字 的方式,数字从 1 开始,代表第几个参数
2.使用 :参数名 的方式,这种方式最好配合 @Param 注解一起使用
案例
/**
* sql 关键字 拼凑
*/
public interface PersonRepository extends JpaRepository<Person,String> {
/**
* 手写 SQl
* 1.如果是 **删改** 操作,需要加上 @Modifying 和 @Transactioinal 注解
* 2.如果是 SQL 语句,请在 @Query 注解上加上 NativeQuery=true 的属性
* 3.传参的方式有2种:
* > 1.使用 ?数字 的方式,数字从 **1** 开始,代表第几个参数
* > 2.使用 :参数名 的方式,这种方式最好配合 **@Param** 注解一起使用
*/
//根据名字来模糊删除一个person数据,Person对应的是实体类名
// personRepository.deleteByName("%zh%");
@Transactional
@Modifying
@Query(value = "delete from Person where pname like :pname")
void deleteByName(@Param("pname") String pname);
//personRepository.deleteByName_b("zh");
@Transactional
@Modifying
@Query(value = "delete from Person where pname like %:pname%")
void deleteByName_b(@Param("pname") String pname);
//
@Query(value = "select p from Person p where p.pname like ?1")
List<Person> findByName_s(String pname);
//HQL
@Query(value = "select p from Person p where p.age between 20 and 30 and p.psex='女'")
List<Person> findByNameHql();
//SQL;nativeQuery = true
@Query(value = "select * from Person where age between 20 and 30 and psex='女'",nativeQuery = true)
List<Person> findByNameSql();
//SQL;nativeQuery = true;参数是单个的值
@Query(value = "select * from Person where age between :lowAge and :highAge and psex=:sex",nativeQuery = true)
List<Person> findByNameSql_parm(@Param("lowAge") Integer lowAge,
@Param("highAge") Integer highAge,
@Param("sex") String sex);
//SQL;nativeQuery = true;参数是对象
@Query(value = "select * from Person where pname=:#{#person.pname}",nativeQuery = true)
List<Person> findByNameSql_parm_p(@Param("person") Person person);
//使用SPEL表达式;参数是对象
@Transactional
@Modifying
@Query(value = "update person set pname=:#{#person.pname},psex=:#{#person.psex},age=:#{#person.age} " +
"where pid=:#{#person.pid}",nativeQuery = true)
void updatePerson(@Param("person") Person person);
//使用SPEL表达式;参数是单个的值
@Transactional
@Modifying
@Query(value = "update person set pname=:#{#p_name},psex=:#{#p_sex},age=:#{#p_age} " +
"where pid=:#{#p_id}",nativeQuery = true)
void updatePerson_dan(@Param("p_name") String name,
@Param("p_sex") String sex,
@Param("p_age") Integer age,
@Param("p_id") String pid);
}
Spring Data JPA 逆向工程操作和多表查询
1.使用数据接口
构建一个数据接口,里面的抽象方法就是SQL语句的查询结果的字段对应的getXXXX的抽象方法;
接收查询字段,必须要为查询的字段名起别名,否则会无法取到
2.使用集合
直接使用 List/Map 等集合嵌套的方式来获取接收数据
3.使用OV (View Object)
单独构建一个跟页面展示数据对应的VO的实体类来接收数据
Book
//IDEA 逆向生成的entity
@Entity
@Table(name = "book", schema = "mall")
public class Book {
private int bid;
private String bname;
private BigDecimal bprice;
private String pid;
@Id
@Column(name = "BID")
public int getBid() {
return bid;
}
public void setBid(int bid) {
this.bid = bid;
}
@Basic
@Column(name = "BNAME")
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
@Basic
@Column(name = "BPRICE")
public BigDecimal getBprice() {
return bprice;
}
public void setBprice(BigDecimal bprice) {
this.bprice = bprice;
}
@Basic
@Column(name = "PID")
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Book that = (Book) o;
return bid == that.bid &&
Objects.equals(bname, that.bname) &&
Objects.equals(bprice, that.bprice) &&
Objects.equals(pid, that.pid);
}
@Override
public int hashCode() {
return Objects.hash(bid, bname, bprice, pid);
}
}
PersonRepository
/**
* sql 关键字 拼凑
*/
public interface PersonRepository extends JpaRepository<Person,String> {
/**
* 手写 SQl
* 1.如果是 **删改** 操作,需要加上 @Modifying 和 @Transactioinal 注解
* 2.如果是 SQL 语句,请在 @Query 注解上加上 NativeQuery=true 的属性
* 3.传参的方式有2种:
* > 1.使用 ?数字 的方式,数字从 **1** 开始,代表第几个参数
* > 2.使用 :参数名 的方式,这种方式最好配合 **@Param** 注解一起使用
*/
//根据名字来模糊删除一个person数据,Person对应的是实体类名
// personRepository.deleteByName("%zh%");
@Transactional
@Modifying
@Query(value = "delete from Person where pname like :pname")
void deleteByName(@Param("pname") String pname);
//personRepository.deleteByName_b("zh");
@Transactional
@Modifying
@Query(value = "delete from Person where pname like %:pname%")
void deleteByName_b(@Param("pname") String pname);
//链表查询-根据书名来查询该书籍拥有者
@Query(value = "select p from Person p inner join Book b on p.pid = b.pid where " +
"b.bname=:bname")
Person findPersonByName(@Param("bname") String bname);
//联表查询 -根据用户id来person和book
//接口来接收查询结果
@Query(value = "select p.pid as pid,p.pname as pname," +
"p.age as page,"+
"p.psex as psex,p.getmarried as getmarried," +
"b.bid as bid,b.bname as bname,b.bprice as bprice " +
"from Person p inner join Book b on p.pid=b.pid " +
"where p.pid=:pid")
List<PersonInfo> findAllInfo(@Param("pid") String pid);
//联表查询 -根据用户id来person和book
//集合Object来接收查询结果
@Query(value = "select p.pid as pid,p.pname as pname," +
"p.age as page,"+
"p.psex as psex,p.getmarried as getmarried," +
"b.bid as bid,b.bname as bname,b.bprice as bprice " +
"from Person p inner join Book b on p.pid=b.pid " +
"where p.pid=:pid")
List<Object> findAllInfo_c(@Param("pid") String pid);
//联表查询 -根据用户id来person和book
//集合Map<String,Object>来接收查询结果
@Query(value = "select p.pid as pid,p.pname as pname," +
"p.age as page,"+
"p.psex as psex,p.getmarried as getmarried," +
"b.bid as bid,b.bname as bname,b.bprice as bprice " +
"from Person p inner join Book b on p.pid=b.pid " +
"where p.pid=:pid")
List<Map<String,Object>> findAllInfo_m(@Param("pid") String pid);
}
网友评论