浅谈JPA框架

JPA

  • 前言
  • 概述
  • ORM 映射元数据
  • JPQL
  • JPA API
    • Spring Data JPA

在这里插入图片描述

前言

了解 JPA 框架对后续使用 Spring Boot 是有很大帮助的,下面简单介绍 JPA 框架的基础知识。

概述

JPA( Java 对象持久化 API ,Java Persistence API ),是 JDK 5.0 平台的标准 ORM(对象关系映射)规范。其核心思想是将运行期的实体对象持久化到数据库中,实现了 Java 对象和数据库表之间的映射关系,使得 Java 开发者能够以面向对象的方式来操作数据库。其主要目标是为 Java 开发者提供一种简单、标准的方式来管理数据库操作,同时避免了手动编写 JDBC 代码和 SQL 语句的繁琐工作,简化了 Java 数据库开发,提高了开发效率和代码质量。通过 JPA ,开发者可以使用高级的 Java 对象来代表数据库中的记录,并使用 JPA 提供的 API 来执行 CRUD(创建、读取、更新、删除)操作。

JPA 框架主要为三个方面的技术:

  • ORM 映射元数据:JPA 支持使用 XML 或 JDK 5.0 注解来描述 Java 对象与数据库表之间的映射关系。这些元数据定义了如何将 Java 对象(实体)映射到关系型数据库中的表,以及如何将表中的记录映射回 Java 对象
  • JPQL:JPA 提供了一种面向对象的查询语言( JPQL ),使开发者可以通过面向对象的方式来查询数据,避免了程序的 SQL 语句紧密耦合
  • JPA API:JPA API 用于操作实体对象,执行 CRUD(创建、读取、更新、删除)操作。开发者可以使用这个 API 进行数据库操作,而无需关心底层的 JDBC 和 SQL 代码

另外,JPA 还提供了事务管理缓存等高级功能,以支持复杂的应用程序需求。

注:
JPA 本身并不是一个完整的 ORM 框架,而是一个规范。具体的 JPA 实现由不同的 ORM 框架提供,如 Hibernate 、EclipseLink 等。这些实现框架遵循 JPA 规范,为开发者提供了具体的 JPA API 实现和额外的功能。

ORM 映射元数据

在 JPA 中,ORM(对象关系映射)映射元数据是一个核心概念。这通常是通过注解( Annotations )和 XML 映射文件的方式来实现。注解通常更简洁,并且与代码紧密集成;而 XML 映射文件则提供了更丰富的配置选项和更好的可读性。在实际应用中,开发者可以根据个人偏好和项目需求来选择其中一种方式来描述 ORM 映射元数据。

简单示例:

1.注解( Annotations )方式

JPA 提供的注解可以直接应用于 Java 类的字段、方法或类级别上。如注解 @Entity 、@Table 、@Column 、@Id 、@GeneratedValue 、@Access 等,这些注解允许开发者直接在 Java 代码中指定实体类与数据库表、实体类字段与数据库列之间的映射关系,而无需编写额外的配置文件。

  • @Entity用于标识一个 Java 类作为 JPA 实体,即该类将被映射到数据库中的一个表。一个实体类通常代表数据库中的一个表
  • @Table用于指定实体类映射的数据库表的信息。如果不使用 @Table 注解,则默认使用实体类的名称作为表名,并且表名会转换为小写(根据 JPA 提供商的实现和配置可能会有所不同)。@Table 注解允许明确指定表名、目录、模式等
  • @Column用于指定实体类属性映射到数据库表中的列的信息。其可以应用于实体类的字段或 getter 方法上。@Column 注解允许指定列名、数据类型、是否可空等
  • @Id用于标识实体类的主键字段或属性。一个实体类必须有一个或多个 @Id 注解的字段或属性,这些字段或属性将映射到数据库表的主键列
  • @GeneratedValue用于指定主键的生成策略。如是否由数据库自动生成还是由应用程序在插入前指定。常见的策略包括 GenerationType.IDENTITY(数据库自增)、GenerationType.SEQUENCE(使用序列)、GenerationType.TABLE(使用 JPA 提供的表来生成主键值)等
  • @Access用于指定访问类型,即 JPA 如何访问实体类的字段或属性。默认情况下,JPA 使用字段访问(即直接访问类的字段),但也可以通过 @Access( AccessType.PROPERTY ) 指定使用属性访问(即通过 getter 和 setter 方法访问)
//@Entity 注解表示 User 类是一个实体类
//@Table 注解定义了实体类映射到哪个数据库表
//@Id 和 @GeneratedValue 注解则标识了主键生成策略
//@Column 注解指定了 name 字段映射到数据库表中的列名为 name

package com.example;  

import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.GenerationType;  
import javax.persistence.Id;  
import javax.persistence.Table;  
import javax.persistence.Column;  

// 用户实体类,表示数据库中的用户
@Entity  
@Table(name = "users")  
public class User {  
    // 用户的唯一标识符  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY) //自增  
    @Column(name = "id")  
    private Long id;  
  
    // 用户的名字  
    @Column(name = "name")  
    private String name;  
  
    // 构造函数  
    public User() {  
        // JPA所需的默认构造函数  
    }  
  
    // 获取 id 的方法  
    public Long getId() {  
        return id;  
    }  
  
    // 设置 id 的方法  
    public void setId(Long id) {  
        this.id = id;  
    }  
  
    // 获取 name 的方法  
    public String getName() {  
        return name;  
    }  
  
    // 设置 name 的方法  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    // 重写 toString 方法,以便更好地调试  
    @Override  
    public String toString() {  
        return "User{" +  
                "id=" + id +  
                ", name='" + name + '\'' +  
                '}';  
    }  
  
    // 重写 equals 和 hashCode 方法,以便正确比较 User 对象  
    @Override  
    public boolean equals(Object o) {  
        if (this == o) return true;  
        if (o == null || getClass() != o.getClass()) return false;  
        User user = (User) o;  
        return id != null ? id.equals(user.id) : user.id == null;  
    }  
  
    @Override  
    public int hashCode() {  
        return id != null ? id.hashCode() : 0;  
    }  
}

2.XML 映射文件方式

JPA 也支持使用 XML 映射文件来描述实体类与数据库表之间的映射关系。这些 XML 文件放置在类路径下的 META-INF 目录中。XML 映射文件提供了更灵活和详细的配置选项,特别是对于复杂的映射场景。

<entity class="com.example.User">  
    <!-- 指定实体类映射的数据库表名 -->  
    <table name="users"/>  
  
    <!-- 定义主键映射 -->  
    <id name="id" type="java.lang.Long">  
        <!-- 指定主键生成策略为自增 -->  
        <generated-value strategy="IDENTITY"/>  
  
        <!-- 指定实体类属性映射到数据库表的列名 -->  
        <column name="id"/>  
    </id>  
  
    <!-- 定义非主键字段映射 -->  
    <basic name="name" type="java.lang.String">  
        <!-- 指定实体类属性映射到数据库表的列名 -->  
        <column name="name"/>  
    </basic>  
</entity>

JPQL

JPQL(Java Persistence Query Language),是一种面向对象的查询语言,其允许开发人员使用实体类和属性来编写查询,而不是直接使用 SQL 语句。这种抽象方式使得应用程序的代码更加简洁、可维护,并且与数据库的具体实现解耦。使用 JPQL ,开发者可以编写类型安全的查询,这些查询在编译时进行检查,从而减少了运行时错误的可能性。JPQL 还支持各种查询操作,如选择、过滤、排序、分组和连接等,这些操作都是使用实体类和属性来完成的。

简单示例:

// 假设有一个名为 User 的实体类,并且已经配置了 JPA  
EntityManager entityManager = entityManagerFactory.createEntityManager();  
  
// 开启事务  
entityManager.getTransaction().begin();  
  
// 创建 JPQL 查询  
String jpql = "SELECT u FROM User u WHERE u.name = :name";  
TypedQuery<User> query = entityManager.createQuery(jpql, User.class);  
  
// 设置查询参数  
query.setParameter("name", "John Doe");  
  
// 执行查询并获取结果  
List<User> users = query.getResultList();  
  
// 处理查询结果  
for (User user : users) {  
    System.out.println("Found user: " + user);  
}  
 
// 提交事务  
entityManager.getTransaction().commit();  

// 关闭 EntityManager  
entityManager.close();

注:
示例中使用了 JPQL 查询语句来选择名为 “John Doe” 的用户。但没有直接编写 SQL 语句,而是使用了实体类 User 和实体属性 name 来构建查询。这种方式使代码更加面向对象,并且更加容易理解和维护。

JPA API

JPA API 的具体用法主要涉及以下方面:

  1. 实体定义

    • 使用 @Entity 注解来标记一个 Java 类作为实体类
    • 使用 @Table 注解来指定实体类映射的数据库表
    • 使用 @Column 注解来指定实体类属性映射的数据库列
    • 使用 @Id 注解来标记实体类的主键属性
  2. 配置持久化单元

    • persistence.xml 配置文件中定义持久化单元,包括指定实体类、数据源、事务管理器等
  3. 创建 EntityManager

    • 通过 EntityManagerFactory 来创建 EntityManager 实例。EntityManager 是 JPA 的核心接口,用于执行数据库操作
  4. 执行 CRUD 操作

    • 使用 EntityManagerpersist() 方法将实体对象保存到数据库中
    • 使用 EntityManagerfind()getReference() 等方法从数据库中查询实体对象
    • 使用 EntityManagermerge() 方法将实体对象合并到持久化上下文中,实现更新操作
    • 使用 EntityManagerremove() 方法从数据库中删除实体对象
  5. 管理事务

    • 使用 EntityManager 的事务管理功能来执行事务操作。可以通过 getTransaction() 方法获取 EntityTransaction 实例,然后调用 begin()commit()rollback() 等方法来管理事务
  6. 查询操作

    • 使用 JPQL 编写查询语句,通过 EntityManagercreateQuery() 方法创建查询对象,然后执行查询并获取结果
  7. 缓存和性能优化

    • JPA 提供了内置的缓存机制,可以通过配置缓存属性来优化性能
    • 使用批量操作、延迟加载等优化手段来进一步提高数据库访问性能
  8. 关闭资源

    • 在使用完 EntityManager 后,需要调用其 close() 方法来关闭,释放相关资源。同时,也需要关闭 EntityManagerFactory

以上是 JPA API 的基本用法,实际上 JPA 还提供了更多高级功能和配置选项,如实体监听器、实体图、自定义查询等。可以根据自己的需求深入学习 JPA API ,并灵活运用到实际项目中。

简单示例:
首先,定义 User 实体类,并且这个类将映射到数据库中的一个表

import javax.persistence.*;  
  
@Entity  
@Table(name = "users")  
public class User {  
  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
  
    @Column(name = "name")  
    private String name;  
  
    @Column(name = "email")  
    private String email;  
  
    // 省略构造函数、getter和setter方法  
    // ...  
}

接着,在 persistence.xml 文件中配置 JPA 的持久化单元

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"  
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence  
                                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"  
             version="2.2">  
    <persistence-unit name="my-persistence-unit" transaction-type="RESOURCE_LOCAL">  
        <class>com.example.User</class>  
        <properties>  
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/mydatabase"/>  
            <property name="javax.persistence.jdbc.user" value="username"/>  
            <property name="javax.persistence.jdbc.password" value="password"/>  
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>  
            <!-- 其他配置属性 -->  
        </properties>  
    </persistence-unit>  
</persistence>

最后,编写一个简单的 JPA 实用类来执行 CRUD 操作

import javax.persistence.*;  
import java.util.List;  
  
public class JpaUtil {  
  
    private static final String PERSISTENCE_UNIT_NAME = "my-persistence-unit";  
  
    public static void main(String[] args) {  
        // 创建 EntityManagerFactory  
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);  
  
        // 创建 EntityManager  
        EntityManager entityManager = entityManagerFactory.createEntityManager();  
  
        try {  
            // 开启事务  
            entityManager.getTransaction().begin();  
  
            // 创建新用户  
            User newUser = new User();  
            newUser.setName("John Doe");  
            newUser.setEmail("john.doe@example.com");  
            entityManager.persist(newUser);  
  
            // 读取用户  
            String jpqlSelect = "SELECT u FROM User u WHERE u.name = :name";  
            TypedQuery<User> selectQuery = entityManager.createQuery(jpqlSelect, User.class);  
            selectQuery.setParameter("name", "John Doe");  
            List<User> users = selectQuery.getResultList();  
            for (User user : users) {  
                System.out.println("Found user: " + user);  
            }  
  
            // 更新用户  
            User userToUpdate = users.get(0);  
            userToUpdate.setEmail("john.doe@updated.com");  
  
            // 删除用户  
            User userToDelete = users.get(1);  
            entityManager.remove(userToDelete);  
  
            // 提交事务  
            entityManager.getTransaction().commit();  
        } catch (Exception e) {  
            // 处理异常  
            if (entityManager.getTransaction().isActive()) {  
                entityManager.getTransaction().rollback();  
            }  
            e.printStackTrace();  
        } finally {  
            // 关闭 EntityManager 和 EntityManagerFactory  
            if (entityManager.isOpen()) {  
                entityManager.close();  
            }  
            if (entityManagerFactory.isOpen()) {  
                entityManagerFactory.close();  
            }  
        }  
    }  
}

注:
在实际的应用程序中,可能会使用 Spring 等框架来管理事务和 EntityManager 的生命周期,而不是手动创建和关闭。此外,异常处理也会更加复杂。

Spring Data JPA

Spring Data ,是 Spring 框架的一个子项目,是一个用于简化数据库访问,并支持云服务的开源框架。其支持多种数据存储技术,包括 JDBC 、JPA 、MongoDB 、 Neo4j 、Redis 和 Hbase 等。Spring Data 通过提供基于 CRUD 操作、查询方法、排序和分页方法等层面的统一接口(如 CrudRepository 和 PagingAndSortingRepository ),来简化对数据持久化层的访问。同时,Spring Data 还通过其 Repository 抽象来减少数据访问层的开发量。这个抽象允许开发者定义接口,而不需要实现,在 Spring Data 运行时会为这些接口生成实现。这极大地简化了数据访问层的开发,提高了开发效率。另外,Spring Data 包含多个子项目(如 Commons 、JPA 、Hadoop 等),每个子项目都针对特定的数据存储技术。这些子项目通过与各种公司和开发者的合作进行开发,以确保其能够满足广泛的需求。

Spring Data JPA ,是 Spring 框架基于 JPA 规范封装的一套 JPA 应用框架,其提供了更加简洁、易用的数据库访问和操作方式,使得开发者能够更加方便地使用 JPA 进行数据库开发。

Spring Data JPA 主要特点

  • Repository 抽象:Spring Data JPA 提供的 Repository 接口,是用于访问数据的通用接口。通过继承或实现这个接口,开发者可以定义数据访问方法,而无需编写具体的实现代码。Spring Data JPA 会在运行时为这些方法生成实现,大大简化了数据访问层的开发
  • 自定义查询:Spring Data JPA 支持使用 JPQL 或原生 SQL 来定义自定义查询。开发者可以通过在 Repository 接口中定义方法,并使用特定的命名约定(如 findBy 、readBy 、getBy 等),来使 Spring Data JPA 自动生成相应的查询
  • 分页和排序:Spring Data JPA 内置了对分页和排序的支持。开发者可以通过在 Repository 接口中定义方法,并使用 Pageable 参数,来实现数据的分页和排序。
  • 事务管理:Spring Data JPA 集成了 Spring 的事务管理功能,使得开发者可以轻松地管理数据库事务
  • 审计和日志:Spring Data JPA 还支持审计和日志功能,可以帮助开发者跟踪数据的修改历史和操作日志
  • 集成 Spring Boot:Spring Data JPA 与 Spring Boot 框架完美集成,使得开发者可以通过简单的配置和注解,快速搭建起一个功能强大的数据访问层

简单示例:
首先,创建一个 Maven 工程( Java 项目)后,在 pom.xml 中添加依赖

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.25</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.3.25</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>5.3.25</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>2.0.6</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-nop -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-nop</artifactId>
      <version>2.0.6</version>
      <type>jar</type>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.20.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>mchange-commons-java</artifactId>
      <version>0.2.20</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.25</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>5.6.15.Final</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-ehcache -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-ehcache</artifactId>
        <version>5.6.15.Final</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.7.8</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

接着,在 resources 目录下分别创建 jdbc.properties 和 log4j.properties,并且进行相关配置

jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdatajpademo?useSSL=false&serverTimezone=UTC
jdbc.user=root
jdbc.password=0123
acquireIncrement=5
initialPoolSize=10
minPoolSize=5
maxPoolSize=100
maxStatements=2
maxStatementsPerConnection=5
#日志级别,分为八个级别( Off-关闭日志记录 > Fatal-严重错误 > Error-错误 > Warn-警告 > Info-运行信息 > Debug-调试 > Trace-低级信息 > All-所有日志记录)
#日志级别越高,过滤的信息越多

#配置根节点
log4j.rootLogger=Debug,stdout,D
#配置控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO
##输出格式(%d %p [%1] %m %n——日期时间 类 路径 信息 换行)
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%l] %m %n

#配置文件输出
log4j.appender.D=org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.Append=true
log4j.appender.D.File=./log4j.log
log4j.appender.D.Threshold=Debug
#输出格式
log4j.appender.D.layout=org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern=%d %p [%l] %m %n

同时,在 resources 目录下创建 spring.xml ,分别进行 spring 配置、spring 与 jpa 整合配置、spring data jpa 配置

<?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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/data/jpa
       http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <!-- spring.xml -->
    <!-- 扫描 SpringDataJPADemo 包 -->
    <context:component-scan base-package="cn.edu.SpringDataJPADemo" />

    <!-- 在 Bean 的外部属性文件的使用中有所提及 -->
    <!-- 使用context命名空间,通过 location 属性指定 properties 文件位置 -->
    <context:property-placeholder location="classpath:jdbc.properties" />
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 连接 MySQL 数据库的基本信息的配置 -->
        <!-- 驱动程序类名:com.mysql.jdbc.Driver -->
        <property name="driverClass" value="${jdbc.driverClass}" />
        <!-- JDBC URL:jdbc:mysql://<host>:<port>/<database_name> -->
        <property name="jdbcUrl" value="${jdbc.url}" />
        <!-- 数据库用户名 -->
        <property name="user" value="${jdbc.user}" />
        <!-- 数据库用户密码 -->
        <property name="password" value="${jdbc.password}" />
        <!-- 若数据库中的连接数量不足时,向数据库申请的连接数量 -->
        <property name="acquireIncrement" value="${acquireIncrement}" />
        <!-- 初始化数据库连接池时连接的数量 -->
        <property name="initialPoolSize" value="${initialPoolSize}" />
        <!-- 数据库连接池最小的数据库连接数 -->
        <property name="minPoolSize" value="${minPoolSize}" />
        <!-- 数据库连接池最大的数据库连接数 -->
        <property name="maxPoolSize" value="${maxPoolSize}" />
        <!-- C3P0 数据库连接池可以维护的 Statement 数量 -->
        <property name="maxStatements" value="${maxStatements}" />
        <!-- 每个连接同时可以使用 Statement 的数量 -->
        <property name="maxStatementsPerConnection" value="${maxStatementsPerConnection}" />
    </bean>

    <!-- 整合 JPA 的配置 -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- JPA 实现产品 -->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>
        <!-- 实体类所在的包 -->
        <property name="packagesToScan" value="cn.edu.SpringDataJPADemo.model" />
        <!-- JPA 实现产品的基本属性 -->
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.enable_lazy_load_no_trans">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <!-- 配置 JPA 事务 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
        <!-- 配置 dataSource -->
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <!-- 配置事务属性 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager" >
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="load*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="read*" read-only="true"/>
            <tx:method name="select*" read-only="true"/>
            <tx:method name="*" read-only="false"/>
        </tx:attributes>
    </tx:advice>

    <!-- 配置事务切入点 -->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* cn.edu.ssmdemo.service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
    </aop:config>

    <!-- 配置 Spring Data JPA -->
    <!-- 将包里的接口自动创建实现类,并把这些实现类放在 Spring IoC 容器中,而在其他层便可以使用 Spring 注解注入对象 -->
    <jpa:repositories base-package="cn.edu.SpringDataJPADemo.dao" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
</beans>

然后,在 MySQL 中创建一个名为 springdatajpademo 的数据库(后面数据表会自动生成)

在这里插入图片描述

随之,创建一个 User 实体类和声明一个持久层接口 UserRepository(继承 Repository ,在接口中声明所需方法,而无需去实现)

package cn.edu.SpringDataJPADemo.model;

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = "user") // 自动生成数据表
public class User {
    private int id;
    private String name;
    private String password;
    private Date regDate;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 自增
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Column(name = "reg_date") // 设置数据表的字段名
    public Date getRegDate() {
        return regDate;
    }

    public void setRegDate(Date regDate) {
        this.regDate = regDate;
    }

    public User() {
        super();
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", regDate=" + regDate +
                '}';
    }
}
package cn.edu.SpringDataJPADemo.dao;

import cn.edu.SpringDataJPADemo.model.User;
import org.springframework.data.repository.Repository;

public interface UserRepository extends Repository<User,Integer> {
    public User getById(int id);
}

最后,创建 UserRepositoryTest 测试类

package cn.edu.SpringDataJPADemo.test;

import cn.edu.SpringDataJPADemo.dao.UserRepository;
import cn.edu.SpringDataJPADemo.model.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserRepositoryTest {

    @Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserRepository userRepository = applicationContext.getBean(UserRepository.class);
        // 运行后,数据表自动生成,自行插入一条信息测试
        User user = userRepository.getById(1);
        System.out.println(user);
    }
}

结果如图:
在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/465341.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

物联网数据驾驶舱

在信息化时代&#xff0c;数据已经成为驱动企业发展的核心动力。特别是在物联网领域&#xff0c;海量数据的实时采集、分析和监控&#xff0c;对于企业的运营决策和业务优化具有至关重要的作用。HiWoo Cloud作为领先的物联网云平台&#xff0c;其数据监控功能以“物联网数据驾驶…

npm包、全局数据共享、分包

使用 npm 包 小程序对 npm 的支持与限制 目前&#xff0c;小程序中已经支持使用 npm 安装第三方包&#xff0c;从而来提高小程序的开发效率。但是&#xff0c;在小程序中使用npm 包有如下 3 个限制&#xff1a; ① 不支持依赖于 Node.js 内置库的包 ② 不支持依赖于浏览器内置…

C++——string

一学习string的原因 1.从个人理解角度上&#xff1a; 在刚开始学习之前&#xff0c;我只知道学习完string在以后的刷题中能提高做题效率&#xff0c;在对字符串的处理string库中也许有对应的接口去实现需求&#xff0c;不用自己去写函数的实现。 但在学string中改变了之前的…

安卓安装Magisk面具以及激活EdXposed

模拟器&#xff1a;雷电模拟器 安卓版本: Android9 文中工具下载链接合集&#xff1a;https://pan.baidu.com/s/1c1X3XFlO2WZhqWx0oE11bA?pwdr08s 前提准备 模拟器需要开启system可写入和root权限 一、安装Magisk 1. 安装magisk 将magisk安装包拖入模拟器 点击&#xff1a…

UnityShader(十六)凹凸映射

前言&#xff1a; 纹理的一种常见应用就是凹凸映射&#xff08;bump mapping&#xff09;。凹凸映射目的就是用一张纹理图来修改模型表面的法线&#xff0c;让模型看起来更加细节&#xff0c;这种方法不会改变模型原本的顶点位置&#xff08;也就是不会修改模型的形状&#xf…

《硬件历险》之Mac抢救出现问题的时间机器硬盘中的数据

本文虽然使用“抢救”一词&#xff0c;但是运气比较好&#xff0c;远没有达到访问和修改底层的信息来抢救的地步。如果你是需要通过访问和修改底层信息来抢救数据&#xff0c;建议阅读刘伟的《数据恢复技术深度揭秘&#xff08;第二版&#xff09;》或者寻找专业人士的帮助。 《…

卷积篇 | YOLOv8改进之C2f模块融合SCConv | 即插即用的空间和通道维度重构卷积

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。SCConv是一种用于减少特征冗余的卷积神经网络模块。相对于其他流行的SOTA方法&#xff0c;SCConv可以以更低的计算成本获得更高的准确率。它通过在空间和通道维度上进行重构&#xff0c;从而减少了特征图中的冗余信息。这种…

留学生课设|R语言|研究方法课设

目录 INSTRUCTIONS Question 1. Understanding Quantitative Research Question 2. Inputting data into Jamovi and creating variables (using the dataset) Question 3. Outliers Question 4. Tests for mean difference Question 5. Correlation Analysis INSTRUCTIO…

深度学习 精选笔记(13.1)卷积神经网络-LeNet模型

学习参考&#xff1a; 动手学深度学习2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、请联系侵删。 ②已写完的笔记文章会不定时一直修订修改(删、改、增)&#xff0c;以达到集多方教程的精华于一文的目的。 ③非常推荐上面&#xff08;学习参考&#x…

SAR ADC教程系列5——FFT频谱泄露以及相干采样

频谱泄露的出现以及如何规避&#xff1f; 为什么要相干采样&#xff1f; 1.分析ADC输出信号的频谱工具&#xff1a;DFT&#xff08;Discrete Fourier Transform) 重点&#xff1a;DFT相邻频谱频率间隔为fs/N 如何规避频谱泄露&#xff1f; 对于DFT&#xff0c;它对于接收到的信…

Qt文件读写

做一个简单的文件读写&#xff0c;我们把一个结构体内的数据写入到二进制文件中&#xff0c;并重新读取解析。代码结构如下&#xff1a; 项目名称随便起就好了。main.cpp是主函数&#xff1b;DataHandler实现文件的写与读&#xff0c;还要模拟过程&#xff1b;Definition.h放置…

机器学习-绪论

机器学习致力于研究如何通过计算的手段、利用经验来改善系统自身的性能。在计算机系统中&#xff0c;“经验”通常以“数据”的形式存在&#xff0c;因此&#xff0c;机器学习所研究的主要内容&#xff0c;是关于在计算机上从数据中产生“模型”的算法&#xff0c;即“学习算法…

NPM 仓库的超集 JSR 来了!

引言 今天在 Deno 博客中看到了一篇文章&#xff0c;介绍了一个叫 JSR 的包管理注册中心&#xff0c;简单尝试了一下觉得还不错&#xff0c;本文将结合原文章和个人体验对 JSR 进行一个详细的介绍。 在现如今的前端开发中&#xff0c;包管理注册中心 (如 npmjs.com) 扮演着至…

Git——本地使用详解

目录 Git1、开始版本控制1.1、初始化Repository1.2、使目录脱离Git控制 2、把文件交给Git管控2.1、创建文件后交给Git2.2、git add之后再次修改文件2.3、git add "--all"与"."参数区别2.4、把暂存区的内容提交到存储库里存档 3、工作区、暂存区与存储库3.1…

Epuck2机器人固件更新及IP查询

文章目录 前言一、下载固件更新软件包&#xff1a;二、查询机器人在局域网下的IP 前言 前面进行了多机器人编队仿真包括集中式和分布式&#xff0c;最近打算在实物机器人上跑一跑之前的编队算法。但由于Epuck2机器人长时间没使用&#xff0c;故对其进行固件的更新&#xff0c;…

软考高级:软件架构本质和作用概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

【PyTorch】进阶学习:一文详细介绍 torch.save() 的应用场景、实战代码示例

【PyTorch】进阶学习&#xff1a;一文详细介绍 torch.save() 的应用场景、实战代码示例 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程…

Vue组件封装方案对比——v-if方式与内置component方式

近期在准备搭建一个通用组件库&#xff0c;而公司现有的各个系统也已有自己的组件库只是没抽离出来&#xff0c;但是目前有两套不同的组件封装方案&#xff0c;所以对于方案的选择比较困惑&#xff0c;于是对两种方式进行了对比&#xff0c;结合网上找到的一些开源组件库进行分…

wireshark解析https数据包

Debian11环境&#xff1a; 在linux环境下抓取访问某个https的网址时抓取的数据包都是加密的&#xff0c;导致无法跟踪到数据包流&#xff0c;现在尝试将抓取的https包进行解密。 1、解密https数据包需要设置SSLKEYLOGFILE变量&#xff0c;推荐写入配置文件中。 echo "exp…

Mysql的行级锁

MySQL 中锁定粒度最小的一种锁&#xff0c;是 针对索引字段加的锁 &#xff0c;只针对当前操作的行记录进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小&#xff0c;并发度高&#xff0c;但加锁的开销也最大&#xff0c;加锁慢&#xff0c;会出现死锁。行级锁和存…