参考网址:
https://tech.souyunku.com6844903486455283720
https://www.jianshu.com/p/c23c82a8fcfc
https://lufficc.com/blog/spring-boot-jpa-basic
1. SpringData JPA概念
1.1 JPA概念
JPA(Java Persistent API)是Sun官方提出的一种Java持久化规范,其目的在于简化持久化开发工作和统一各种ORM(Object Relationship Mapping)框架。需要注意的是JPA本身只是一个标准,定义了一系列规范,并不提供响应的实现。
ORM
参考网址:
http://www.ruanyifeng.com/blog/2019/02/orm-tutorial.html
ORM可以简单理解为将对象和数据库实体关系映射起来,这种映射关系主要表现为:
- 类 <->数据库表
- 对象 <-> 数据记录
- 对象的属性 <-> 数据库的字段
1.2 Spring Data JPA
Spring Data JPA 是 Spring 基于ORM框架、JPA规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。
2. SpringBoot集成Spring Data JPA
2.1 引入jar包
引入SpringDataJpa和mysql依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql驱动:com.mysql.jdbc.Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
2.2 修改配置文件
在application.properties里增加数据库连接的相关配置,示例如下:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=true
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
jpa:
database: mysql
#自动建表
hibernate:
ddl-auto: validate
#设置数据库方言
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
#打印sql
show-sql: true
数据库命名风格:
关于实体类名和数据库表名、实体字段名与数据库列名的关系,建议使用无修改命名(更符合Java的驼峰式命名),需要添加如下配置:
参考网址:
spring:
jpa:
hibernate:
naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
naming.physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
2.3 创建实体类
(0)提前建立数据库和表
(1)实体类添加@Entity注解
一般还添加注解@Data,用于省去getter、setter方法。
还可以使用@Table注解指定对应的表名,不加@Table注解的话则是类首字母变小写的表(除首字母以外还未测试)
@Table(name = "user", schema = "test", catalog = "")
name是表名,schema是数据库名,不写则是配置文件中的数据库。
实体类还可以添加@DynamicInsert注解。
// 表示动态插入,如果某字段为空,那么使用数据库中配置的默认值,当然也可以在实体类中设置默认值
@DynamicInsert
(2)主键属性需要添加@Id注解
@Id注解表示该列是一个主键列
还可以设置id生成策略,默认为auto,表示由数据库生成:
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonIgnore
private Long id;
(3) 其它属性可以添加@Column注解
可以设置属性在数据库中的对应的字段名,不设置的话应该是同名 @Column(name = “password”)
(4)枚举类型可以添加@Enumerated注解
实际测试在枚举类型上如果不加任何注解的话,存储到数据库时会自动将枚举序数存到数据库。
也可使用Enumerated注解来将枚举的String值存储到和数据库。
/**
* EnumType: ORDINAL 枚举序数 默认选项(int)
* STRING:枚举toString()返回值 (String)
*/
@Enumerated(EnumType.STRING)
还可以使用@Column注解来设置字段在数据库对应的数据类型,比如默认枚举序列在Java中是int类型,这时候可以讲其配置成TINYINT类型。
@Column(columnDefinition = "TINYINT")
(5)时间日期类型可以添加@Temporal注解来设置时间字段在数据库中对应字段的类型
第一种:@Temporal(TemporalType.DATE)——>实体类会封装成日期“yyyy-MM-dd”的 Date类型。
第二种:@Temporal(TemporalType.TIME)——>实体类会封装成时间“hh-MM-ss”的 Date类型。
第三种:@Temporal(TemporalType.TIMESTAMP)——>实体类会封装成完整的时间“yyyy-MM-dd hh:MM:ss”的 Date类型。
(6)数据库中没有的字段可以添加@Transient注解
使用@Transient注解表示该字段不是一个数据库表中字段
(7)可以为数据库中前缀相同的列建立实体类,并使用@Embedded和@Embeddable注解
如下面
@Embedded
@AttributeOverrides(value = {
@AttributeOverride(name = "id", column = @Column(name = "departmentId")),
@AttributeOverride(name = "name", column = @Column(name = "departmentName")),
})
private Department department;
@Embeddable
@Data
public static class Department {
public String id;
public String name;
}
2.4 创建DAO接口类
创建Dao接口,无需创建实现类,继承JpaRepository或CrudRepository接口(JpaRepository继承了CrudRepository),并声明对象类型和ID类型。形如:
public interface UserDao extends JpaRepository<User, Long>
在controller和service层,可直接注入dao bean,并调用其中的方法。
@Autowired
private UserDao userDao;
2.5 编写查询方法
(1)内置方法
Repository有许多可直接使用的方法(无需定义),比如:
count();
findById(id);
findAll();
save(user);
delete(user);
deleteById(id);
(2)简单查询
Repository可以根据接口方法名按照一定规则进行简单查询。
规则:
find+全局修饰+By+实体属性名称+限定词+连接词+(其他实体属性)+OrderBy+排序属性+排序方向
全局修饰符:distinct、top、first
限定词:IsNull、IgnoreCase
排序方向:Asc、Desc
例如:
User findByUserId(String userId);
List<User> findByName(String userName);
(3)定义查询语句
i. 在DAO接口中声明方法;
ii. 在方法上添加@Query注解,value = “语句”,注意查询语句中使用实体类的名和对应字段名。
iii. 可以使用 ?1 ?2 来传递参数,与方法的参数顺序一致。或者可以使用@Param来命名参数。
示例:
@Query(value = "select id from User where userId=:userId and name=:userName")
Long findByUserIdAndUserName(@Param("userId") String userId, @Param("userName") String userName);
@Query(value = "select id from User where userId=?1 and name=?2")
Long findByUserIdAndUserName2(String userId, String userName);
2.6 配置文件、sql脚本,实体类、dao完整代码
配置文件:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=true
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
jpa:
database: mysql
#自动建表
hibernate:
ddl-auto: validate
naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
naming.physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
#设置数据库方言
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
#打印sql
show-sql: true
sql脚本:
DROP TABLE IF EXISTS `User`;
CREATE TABLE `User` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '记录ID',
`userId` varchar(40) NOT NULL COMMENT '用户ID',
`userName` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
`status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '用户状态',
`createTime` timestamp NOT NULL DEFAULT '2010-01-01 00:00:00' COMMENT '创建时间',
`updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`departmentId` varchar(40) NOT NULL DEFAULT '' COMMENT '部门ID',
`departmentName` varchar(40) NOT NULL DEFAULT '' COMMENT '部门名',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_userid` (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '用户表';
实体类:
/**
* @author :jiangwang01
* Created in 2020-01-16 21:01
*/
@Data
@Entity
// 表示动态插入,如果某字段为空,那么使用数据库中配置的默认值,也可以在实体类中设置默认值
@DynamicInsert
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonIgnore
private Long id;
private String userId;
@Column(name = "userName")
private String name;
@Enumerated(value = EnumType.ORDINAL)
@Column(columnDefinition = "TINYINT")
@JsonIgnore
private Status status;
@Embedded
@AttributeOverrides(value = {
@AttributeOverride(name = "id", column = @Column(name = "departmentId")),
@AttributeOverride(name = "name", column = @Column(name = "departmentName")),
})
private Department department;
@JsonIgnore
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
@JsonIgnore
@Temporal(TemporalType.TIMESTAMP)
private Date updateTime;
public enum Status {
CREATING, ACTIVE, INACTIVE
}
@Embeddable
@Data
public static class Department {
public String id;
public String name;
}
}
Dao:
public interface UserDao extends JpaRepository<User, Long> {
Optional<User> findById(Long id);
User findByUserId(String userId);
List<User> findByName(String userName);
@Query(value = "select id from User where userId=:userId and name=:userName")
Long findByUserIdAndUserName(@Param("userId") String userId, @Param("userName") String userName);
@Query(value = "select id from User where userId=?1 and name=?2")
Long findByUserIdAndUserName2(String userId, String userName);
}