Spring Data Jpa 基本使用及解析

it2024-12-07  13

ORM规范

ORM:O->Object、R->Relational (关系)、M-> Mapping(映射),即对象-关系映射

是将数据库关系映射成实体类的思想

例如JPA中:

数据库表table对应实体类,列Column对应实体类成员变量 这样就不需要自己先创建表,而是由JPA根据实体类来创建


Jpa/Hiberante/Spring Data Jpa的关系

JPA是ORM规范Hibernate是Jpa规范的具体实现Spring Data Jpa封装了Hibernate,添加另一层抽象(Repository层的实现),极大地简化持久层开发及ORM框架切换的成本。

Springboot集成JPA

一个简单的Springboot-JPA的Demo

结构:暂时只用Repository层、entity层及测试

Maven依赖

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>JPATest</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <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> </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> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

数据库及JPA配置

application.yml:

spring: datasource: username: root password: root url: jdbc:mysql://localhost:3306/jpa?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false jpa: # 设置数据库类型(可使用org.springframework.orm.jpa.vendor包下的Database枚举类) database: mysql # 设置是否打印sql语句 show-sql: true hibernate: # 每次运行程序,没有表时会创建表,如果对象发生改变会更新表结构,原有数据不会清空,只会更新 ddl-auto: update # 设置hibernate方言,对应mysql的版本,解决mysql与hibernate版本不对应问题 database-platform: org.hibernate.dialect.MySQL8Dialect

实体类

User类:

package demo.entity; import lombok.Data; import org.hibernate.annotations.GenericGenerator; //java提供的持久层注解 import javax.persistence.*; import static javax.persistence.GenerationType.IDENTITY; /** * Author : zfk * Date : 14:12 */ @Entity @Table(name = "user_") @Data public class User { @Id //JPA接口,IDENTITY主键自增 @GeneratedValue(generator = "idGenerator",strategy = IDENTITY) private String id; //Column 数据库表列,unique不可重复,nullable不可为空 @Column(name = "username_",unique = true,nullable = false) private String username; @Column(name = "password_") private String password; @Column(name = "email_",length = 64) private String email; }

Repository

持久层,因为JPA自带了很多find方法,内置了sql语句,所有简单的查询不需要写sql

package demo.dao; import demo.entity.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; /** * Author : zfk * Date : 14:31 */ public interface UserRepository extends JpaRepository<User,String> { User findByUsername(String name); }

测试方法

package demo; import demo.dao.UserRepository; import demo.entity.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.Optional; @SpringBootTest class DemoApplicationTests { @Autowired private UserRepository repository; @Test void contextLoads() { Optional<User> user = repository.findById("1"); User zhang = repository.findByUsername("zhang"); System.out.println("findById : "+user.get()); System.out.println("findByName : "+zhang); } }

结果:

详细代码地址 - gitee


基于Spring

springboot简化了配置,如果是spring的话就有些麻烦:

spring.xml配置:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd" default-lazy-init="true"> <!-- 扫描service包下所有使用注解的类型 --> <context:component-scan base-package="com.service"/> <!-- 属性文件位置 --> <context:property-placeholder location="classpath:jdbc.properties" /> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!--2 工 工厂类对象--> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <!--配置数据源--> <property name="dataSource" ref="dataSource"/> <!--实体类的包扫描--> <property name="packagesToScan" value="com.entity"/> <!--设置实现厂商JPA实现的特定属性--> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="true"/> <property name="generateDdl" value="true"/> <property name="database" value="MYSQL"/> </bean> </property> </bean> <!-- 设置JPA实现厂商的特定属性 --> <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="databasePlatform" value="${hibernate.dialect}"/> <!--自动检查注解的实体和数据表,如果数据库不存在表,会根据实体自动生成--> <property name="generateDdl" value="true"/> </bean> <!-- Jpa 事务配置 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- Spring Data Jpa配置 --> <jpa:repositories base-package="com.repository" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"/> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> </beans>

关于JPA配置

Springboot可以在yml文件设置,当然也可以自定义配置类 配置的相关属性在JpaProperties中定义

有以下5个属性

database数据库类型:由org.springframework.orm.jpa.vendor包下的Database枚举类提供

Spring只提供了这些关系型数据库:

database-platform:设置hibernate方言,根据我们选的数据库对应数据库的版本,解决数据库与hibernate版本不对应问题 在org.hibernate.dialect包下,对应了很多数据库版本

如mysql:

show-sql:是否打印sql语句

上述例子就是打印了sql语句:

openInView:在事务外也可以访问懒加载的数据

generateDdl:项目启动时自动检查注解的实类和数据库表,当数据库表或者字段不存在时,则出具库自动添加相应字段。如果数据库存在的字段,而实体中没有属性则不会自动删除数据库字段

实际上用HibernateProperties的配置即可,ddl-auto有四种参数

create ----每次运行该程序,没有表格会新建表格,表内有数据会清空 create-drop ----每次程序结束的时候会清空表 update ---- 每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新 validate ---- 运行程序会校验数据与数据库的字段类型是否相同,不同会报错


关于JPA注解

JPA注解主要是实体类与数据库映射

@Entity:标记一个类为实体类,添加该注解后,会在数据库中创建一个和类名相同的表@Table:当实体类与其映射的数据表名称不一致时,需要使用该注解标注,该注解与Entity注解并列使用,置于实体类注解之前,可以设置3个参数:name:数据库的表名、catalog:数据库目录、schema:数据库模式@Column:实体类属性映射成数据库表的一列,当属性名与列名不同时,可以通过name属性设置@Transient:使用该注解当前属性不需要映射为数据表的一列@ID:声明主键@GeneratedValue:设置主键的生成策略,通过strategy属性指定,有四种策略:

IDENTITY:采用数据库 ID 自增长的方式来自增主键字段,Oracle 不支持。 AUTO:JPA 自动选择合适的策略,默认选项。 SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySQL 不支持。 TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植

当需要自定义主键生成策略,如使用uuid时就可以使用@GenericGenerator注解,需要@GenericGenerator和 @GeneratedValue一起使用

@Id @GeneratedValue(generator = "idGenerator") @GenericGenerator(name = "idGenerator", strategy = "uuid") private String id;

如果自定义主键生成策略,需要重写IdentifierGenerator 接口


关于JpaRepository

通过实现JpaRepository接口可以大大简化数据访问代码

JPA支持接口规范方法名查询,如果在接口中定义的查询方法符合它的命名规则,就可以不用写实现,不符合规范会报错,需要添加@Query注解

JPA会进行方法名解析,如findByUsernam,先把前缀findBy剔除,然后根据绑定的实体类,解析剩下的部分

绑定了User,就去User中查询username属性,存在即根据该属性进行查询

其他更复杂的方法也是根据上述命名规范解析方法名

最新回复(0)