做网站需要到哪些部门登记,上海外贸50强企业,网站的建设目标是什么意思,百度游戏中心目录
一、SpringData JPA 概述
1.1、什么是 JPA
1.2、什么是 ORM
1.3、什么是 Hibernate
1.4、JPA 和 Hibernate 的关系
1.5、JPA 的优势
二、SpringData JPA 实战开发
2.1、依赖
2.2、配置文件
2.3、启动类
2.4、创建实体
2.5、基于 JpaRepository 的 CRUD
三、…目录
一、SpringData JPA 概述
1.1、什么是 JPA
1.2、什么是 ORM
1.3、什么是 Hibernate
1.4、JPA 和 Hibernate 的关系
1.5、JPA 的优势
二、SpringData JPA 实战开发
2.1、依赖
2.2、配置文件
2.3、启动类
2.4、创建实体
2.5、基于 JpaRepository 的 CRUD
三、SpringDataJPA 多种查询方式
3.1、JpaRepository 查询
3.2、方法命名规则查询
3.3、JPQL 查询
3.4、SQL 查询
3.5、JpaSpecificationExecutor 动态查询 一、SpringData JPA 概述 1.1、什么是 JPA
全英文名叫 Java Persistence API就是 java 持久化 api 是SUN公司推出的一套基于 ORM 的规范。 1.2、什么是 ORM
ORMObject Relational Mapping表示对象关系映射. 简单来讲通过 ORM就可以把对象映射到关系型数据库中为了不用 JDBC 那套方法来操作数据库. 1.3、什么是 Hibernate
Hibernate 是一个对象关系映射框架对 JDBC 进行了非常轻量级的封装将 对象 与 数据库 简历映射关系一个全自动的 ORM 框架. Hibernate 可以自动生成 SQL 语句自动执行使得 Java 程序员可以通过面向对象的思想来操纵数据库. 1.4、JPA 和 Hibernate 的关系
JPA 和 Hibernate 的关系就像 JDBC 和 JDBC驱动 的关系JPA 是规范Hibernate 除了作为 ORM 框架之外也是一种 JPA 实现.
简单来讲如果使用 JPA 规范数据库操作底层需要 Hibernate 作为其实现完成持久化. 1.5、JPA 的优势
a标准化
JPA 是 Java EE 标准之一因此任何声称符合 JPA 标准的框架都需要遵循同样的框架提供相同的 API大大提高了可移植性性.
b特性支持
JPA 框架支持大数据集、事务、并发等容器级事务在大型企业中发挥极大作用.
c使用方便
JPA 的主要目标之一就是提供更加简单的编程模型在 JPA 框架下创建实体和创建 Java 类一样简单没有任何限制和约束只需要使用 javax.persistence.Entity 注解. 另外还提供很多基础 CRUD避免重复造轮子
d高级特性
JPA 中支持面向对象的高级特性例如 类之间的继承、多态... 使得开发者最大限度的使用面向对象的模型设计企业应用. 二、SpringData JPA 实战开发 2.1、依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.49/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency2.2、配置文件
server:port: 9000spring:datasource:url: jdbc:mysql://localhost:3306/jpa?characterEncodingutf8useSSLfalseusername: rootpassword: DJSAKOFH0*)(shdf*s*_(fsbpf*s)_fg*_fg{!p_#*t_!bfugiwofhgdriver-class-name: com.mysql.jdbc.Driverjpa:database: mysqlshow-sql: true # 显示 sql 语句项目上线后记得关闭hibernate:ddl-auto: updateopen-in-view: false # 一般来讲建议关闭ddl-auto 熟悉用于设置自动表可以实现自动在数据库中为我们创建一个表表的结构会根据我们定义的实体类决定具体有 4 种值
create启动时删除数据库中表然后创建退出时不删除数据表.create-drop启动时删除数据库中表然后创建退出时删除数据表并且如果不存在就报错.update如果启动时表格式不一致则更新表原有数据保留validate项目启动时表结构进行校验不一致则报错.none不采取任何措施. Ps表可以是自动创建的但是数据库必须我们手动创建. 2.3、启动类
EnableJpaAuditing //用来开启 JPA 审计功能
SpringBootApplication
class JpaApplicationfun main(args: ArrayString) {runApplicationJpaApplication(*args)
}EnableJpaAuditing 用来开启 JPA 审计功能比如在建表中经常会加入 版本号、创建时间、修改时间、创建者、修改者 这五个字段. 为了简化开发可以将其交给 JPA 来自动填充. 2.4、创建实体
import com.fasterxml.jackson.annotation.JsonFormat
import org.springframework.data.annotation.CreatedBy
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedBy
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.util.*
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.EntityListeners
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.persistence.Table
import javax.persistence.VersionEntity
Table(name user_info)
EntityListeners(AuditingEntityListener::class)
data class Userinfo(IdGeneratedValue(strategy GenerationType.IDENTITY)val id: Long? null,val username: String,val age: Int,//注意关于审计信息都需要使用 var 类型Versionvar version: Long? null,CreatedByColumn(name c_by)var cBy: String? null,LastModifiedByColumn(name u_by)var uBy: String? null,CreatedDatefield:JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8)Column(name c_time)var cTime: Date? null,LastModifiedDatefield:JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8)Column(name u_time)var uTime: Date? null,)注解作用常用属性Data给实体类加get/set/toString/EqualsAndHashCode方法是lombok的注解Entity指定当前类是实体类Table指定实体类和表之间的对应关系name指定数据库表的名称EntityListeners在实体类增删改的时候监听为创建人/创建时间等基础字段赋值value指定监听类Id指定当前字段是主键SequenceGenerator指定数据库序列别名sequenceName数据库序列名 name取的别名GeneratedValue指定主键的生成方式strategy 指定主键生成策略一般设置 为GenerationType.IDENTITY表示自增长 generator选择主键别名Column指定实体类属性和数据库表之间的对应关系如果成员变量名和表字段名对应一致可以省略name指定数据库表的列名称。 unique是否唯一 nullable是否可以为空 nserttable是否可以插入 updateable是否可以更新 columnDefinition: 定义建表时创建此列的DDLCreatedBy自动插入创建人CreatedDate自动插入创建时间LastModifiedBy自动修改更新人LastModifiedDate自动修改更细时间Version自动更新版本号JsonFormat插入/修改/读取的时间转换成想要的格式pattern展示格式 timezone国际时间 解释 a主键策略
SEQUENCE 策略适合拥有序列的数据库比如 OracleIDENTITY 策略适合拥有主键自增长的数据库比如 MySQLTABLE 策略是通过一张序列表来维护主键插入的值的所以适合所有数据库AUTO 策略是 JPA 自行判断使用上面三个中的哪一个作为主键生成策略
开发人员应该自行判断使用的是何种数据库而不是由 JPA 进行判断。
b审计功能
Version版本号进行 update 操作时启动乐观锁Version 修饰的字段值与数据库中字段值一致才能进行修改CreatedDate 创建时间进行 insert 操作时将当前时间插入到 CreatedDate 修饰字段中进行 update 操作时会随实体类中的 CreatedDate 修饰的字段值进行修改CreatedBy创建人进行 insert 操作时将当前用户名插入到 CreatedBy 修饰字段中进行update操作时会随实体类中的 CreatedBy 修饰的字段值进行修改LastModifiedDate最后一次修改时间进行 update 操作时将当前时间修改进LastModifiedDate 修饰字段中进行 insert 操作时将当前时间插入到 LastModifiedDate 修饰字段中LastModifiedBy 最后一次修改的修改人进行 update 操作时将当前修改人修改进LastModifiedBy 修饰的字段中进行 insert 操作时将当前用户名插入到LastModifiedBy修饰字段中
c启动审计条件
启动类上有 EnableJpaAuditing 注解.实体类上方加上监听注解 EntityListeners(AuditingEntityListener::class)
完成上述两个注解后CreatedDate、LastModifiedBy、Version 就生效了但是创建人、修改人不会生效需要我们创建一个配置类实现 AuditorAwareString 接口如下
Configuration
class UserAuditor: AuditorAwareString {/*** return 获取当前创建或修改的用户*/override fun getCurrentAuditor(): OptionalString {return Optional.of(我是审计者 cyk) }}Ps正式项目中一般会从 JWT 或者 Session 中获取当前操作该表的用户是谁. 2.5、基于 JpaRepository 的 CRUD
Spring Data JPA 操作数据库只需要自定有接口并继承 JpaRepository 接口无需再接口中定义任何方法也不需要为接口提供实现类就能完成基本 CRUD.
a接口
import org.cyk.jpa.model.Userinfo
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.RepositoryRepository
interface UserRepoJpa: JpaRepositoryUserinfo, Longb测试类
import org.cyk.jpa.model.Userinfo
import org.cyk.jpa.repo.UserRepoJpa
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import javax.annotation.ResourceSpringBootTest
class JpaApplicationTests {Resourceprivate lateinit var userRepoJpa: UserRepoJpaTestfun test() {val obj Userinfo(username cyk3,age 21,)userRepoJpa.save(obj)val result userRepoJpa.findAll()result.forEach(::println)}}执行结果 Ps创建人和更新人埋坑最后会补充~ cSpringDataJPA 的接口继承关系
Repository (标记接口、做标记、Repository接口的子接口的实现类对象可以自动被SpringIOC容器所识别此接口的子接口中可以定义一些指定规范的方法)||
CrudRepository (定义了一些基本的CRUD方法)||
PagingAndSortingRepository (定义了排序和分页相关的查询方法)||
JpaRepository (重写了一些基本测CRUD方法)||
ArticleDao (自己定义的接口) 三、SpringDataJPA 多种查询方式 3.1、JpaRepository 查询
a只需要创建一个接口让他继承 JpaRepositoryT, ID 接口即可
T实体类IDid 类型
import org.cyk.jpa.model.Userinfo
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.RepositoryRepository
interface UserRepoJpa: JpaRepositoryUserinfo, Long此时你就可以直接使用 JpaRepositoryT, ID 接口 提供的方法 b测试
import org.cyk.jpa.model.Userinfo
import org.cyk.jpa.repo.UserRepoJpa
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import javax.annotation.ResourceSpringBootTest
class JpaApplicationTests {Resourceprivate lateinit var userRepoJpa: UserRepoJpaTestfun test() {val obj Userinfo(username cyk3,age 21,)userRepoJpa.save(obj)val result userRepoJpa.findAll()result.forEach(::println)}}3.2、方法命名规则查询
a创建一个接口继承 JpaRepository 接口此时你就可以自定义一些方法方法名有要求SpringDataJPA 就会再程序执行的时候根据方法名进行解析自动生成对应的查询语句.
b规范 查询起始词查询方法通常以 find、read、get、query、count、exists 等词开头。 属性引用在起始词之后你可以引用实体类的属性名首字母大写。例如如果有一个名为 firstName 的属性你可以通过 findByFirstName 来查询它。 条件组合对于多个条件你可以使用 And 或 Or 连接。例如findByFirstNameAndLastName 会查找同时匹配 firstName 和 lastName 的记录。 排序你可以使用 OrderBy 关键字并指定属性名和排序方向如 Asc 或 Desc来排序结果。 限制结果使用 First、Top 或 Limit 可以限制返回的记录数。例如findFirstByName 会返回按 name 排序后的第一个结果。 聚合函数Spring Data JPA 也支持聚合函数如 countBy、sumBy、avgBy 等。 处理特殊情况如果属性名包含特殊字符或与 SQL 关键字冲突可以使用 Column 注解来明确指定字段名。对于复杂的查询可以使用 Query 注解来编写自定义的 SQL 或 JPQL 查询。 命名规范属性名在方法名中通常是大写的以符合 Java 的命名规范即使它们在数据库或实体类中是小写的。 分页如果需要分页查询可以在方法参数中添加 Pageable 类型的参数。 流和迭代除了返回列表或单个实体方法还可以返回流Stream或迭代器Iterable以支持更高效的内存使用。
例如
import org.cyk.jpa.model.Userinfo
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.RepositoryRepository
interface UserRepoName: JpaRepositoryUserinfo, Long {//直接查询fun findByUsername(username: String): ListUserinfo//模糊查询fun findByUsernameLike(username: String): ListUserinfo//and 查询fun findByUsernameAndAge(username: String, age: Int): ListUserinfo//小于等于查询fun findByIdLessThanEqual(id: Long): ListUserinfo//between 查询fun findByIdBetween(start: Long, end: Long): ListUserinfo//in 查询fun findByIdIn(ids: ListLong): ListUserinfo}测试
import org.cyk.jpa.repo.UserRepoName
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import javax.annotation.ResourceSpringBootTest
class JpaNameApplicationTests {Resourceprivate lateinit var userRepoName: UserRepoNameTestfun test1() {userRepoName.findByUsername(cyk).forEach(::println)}Testfun test2() {userRepoName.findByUsernameLike(%y%).forEach(::println)}Testfun test3() {userRepoName.findByUsernameAndAge(cyk, 21).forEach(::println)}Testfun test4() {userRepoName.findByIdLessThanEqual(2).forEach(::println)}Testfun test5() {userRepoName.findByIdBetween(1, 3).forEach(::println)}Testfun test6() {userRepoName.findByIdIn(listOf(1,2)).forEach(::println)}}3.3、JPQL 查询
JPQL全称是 Java 持久化查询语言是 JPA 中定义的一种查询语言. 此种语言的用意是让开发者忽略数据库表和表中的字段而关注实体类及实体类中的属性。
写法十分类似于SQL语句的写法但是要把查询的表名换成实体类的名称把表中的字段名换成实体类的属性名称。
接口
import org.cyk.jpa.model.Userinfo
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import org.springframework.stereotype.RepositoryRepository
interface UserRepoJpql: JpaRepositoryUserinfo, Long {//占位符从 1 开始Query(from Userinfo where username ?1 and age ?2)fun findByCond1(username: String, age: Int): ListUserinfo//参数名 : 绑定Query(from Userinfo where username :username and age :age)fun findByCond2(Param(username) username: String,Param(age) age: Int): ListUserinfo//模糊查询 排序Query(from Userinfo where username like %:username% order by cTime desc)fun findByCond3(Param(username) username: String): ListUserinfo//模糊查询 分页Query(from Userinfo where username like %:username%)fun findByCond4(pageable: Pageable, Param(username) username: String): ListUserinfo//in 查询Query(from Userinfo where age in :ages)fun findByCond5(Param(ages) ages: ListInt): ListUserinfo//通过对象进行查询(SPEL 表达式查询)Query(from Userinfo where username :#{#userinfo.username} and age :#{#userinfo.age})fun findByCond6(Param(userinfo) userinfo: Userinfo): ListUserinfo}测试
import org.cyk.jpa.model.Userinfo
import org.cyk.jpa.repo.UserRepoJpql
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.data.domain.PageRequest
import javax.annotation.ResourceSpringBootTest
class JpaJpqlApplicationTests {Resourceprivate lateinit var userRepoJpql: UserRepoJpqlTestfun test1() {userRepoJpql.findByCond1(cyk, 21).forEach(::println)}Testfun test2() {userRepoJpql.findByCond2(cyk, 21).forEach(::println)}Testfun test3() {userRepoJpql.findByCond3(y).forEach(::println)}Testfun test4() {val pg PageRequest.of(1, 2)userRepoJpql.findByCond4(pg, y).forEach(::println)}Testfun test5() {userRepoJpql.findByCond5(listOf(21,22,23)).forEach(::println)}Testfun test6() {userRepoJpql.findByCond6(Userinfo(username cyk,age 21)).forEach(::println)}}3.4、SQL 查询
在 Query 注解中设置属性 nativeQuery true表示使用 SQL 语句进行查询.
基本不会使用这种情况除非是非常复杂的业务情况.
接口
import org.cyk.jpa.model.Userinfo
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Queryinterface UserRepoSql: JpaRepositoryUserinfo, Long {Query(value select * from user_info where username ?1 and age ?2, nativeQuery true)fun findByCond(username: String, age: Int): ListUserinfo}测试
import org.cyk.jpa.repo.UserRepoSql
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import javax.annotation.ResourceSpringBootTest
class JpaSqlApplicationTests {Resourceprivate lateinit var userRepoSql: UserRepoSqlTestfun test() {userRepoSql.findByCond(cyk, 21).forEach(::println)}}3.5、JpaSpecificationExecutor 动态查询
类似我们写动态 SQL给定的条件不是固定的需要动态的构建查询语句.
SpringDataJPA 中我们只需要自定义个接口继承 JpaRepository 和 JpaSpecificationExecutor 接口即可.
接口
import org.cyk.jpa.model.Userinfo
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.JpaSpecificationExecutor
import org.springframework.stereotype.RepositoryRepository
interface UserRepoJpaSpe: JpaRepositoryUserinfo, Long, JpaSpecificationExecutorUserinfo测试
import org.cyk.jpa.model.Userinfo
import org.cyk.jpa.repo.UserRepoJpaSpe
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort
import org.springframework.data.jpa.domain.Specification
import javax.annotation.Resource
import javax.persistence.criteria.PredicateSpringBootTest
class JpaSpeApplicationTests {Resourceprivate lateinit var userRepoJpaSpe: UserRepoJpaSpe//username 和 age 不为空才作为查询条件Testfun test1() {//模拟外部输入val username: String? val age: Int? 21/*** 拼接查询条件* root: 代表实体对象可以通过它获取属性值* cq: 用于生成SQL语句* cb: 用于拼接查询条件*/val s SpecificationUserinfo { root, cq, cb -val predicates mutableListOfPredicate()if (!username.isNullOrBlank()) {val p cb.equal(root.getString(username), username)predicates.add(p)}age?.let {val p cb.equal(root.getInt(age), it)predicates.add(p)}cb.and(*predicates.toTypedArray())}//查询userRepoJpaSpe.findAll(s).forEach(::println)}//查询 分页 排序倒序Testfun test2() {//模拟外部输入val username: String? val age: Int? 21/*** 拼接查询条件* root: 代表实体对象可以通过它获取属性值* cq: 用于生成SQL语句* cb: 用于拼接查询条件*/val s SpecificationUserinfo { root, cq, cb -val predicates mutableListOfPredicate()if (!username.isNullOrBlank()) {val p cb.equal(root.getString(username), username)predicates.add(p)}age?.let {val p cb.equal(root.getInt(age), it)predicates.add(p)}cb.and(*predicates.toTypedArray())}//分页 排序val pg PageRequest.of(0, 3, Sort.by(Sort.Order.desc(cTime))) //注意这里对应的是成员变量名(而非表中的字段名)val result userRepoJpaSpe.findAll(s, pg)result.forEach(::println)}}