当前位置:   article > 正文

【SpringBoot整合JPA框架(hibernate实现)详解】(附详细代码)

jpa框架

一、JPA框架详解

1. JPA简介

Java Persistence API(JPA)是Java EE和Java SE平台的一部分,提供了一种简单的对象关系映射(ORM)机制,用于将Java对象持久化到关系型数据库中。JPA通过注解或XML配置文件实现实体类与数据库表之间的映射,简化了数据库操作的过程。

2. JPA核心接口

2.1 EntityManagerFactory

EntityManagerFactory是JPA的核心接口,用于创建EntityManager实例。通常在一个应用程序中只创建一个EntityManagerFactory实例,并通过单例模式或者池化管理。

2.2 EntityManager

EntityManager是JPA的核心接口,用于执行数据库操作,如插入、更新、删除和查询。每个线程只能有一个EntityManager实例。

2.3 EntityTransaction

EntityTransaction是一个事务对象,用于定义一组操作的原子性。事务具有以下四个属性:隔离级别、传播行为、超时时间和只读属性。

3. JPA实体类与数据库表的映射

3.1 @Entity

@Entity注解用于标记一个类为实体类,表示该类将被持久化到数据库中。通常需要为主键字段添加@Id注解,其他属性使用@Column注解进行映射。

3.2 @Table

@Table注解用于指定实体类对应的数据库表名。如果需要指定多个表名,可以使用@Table(name = "table_name")的方式。

3.3 @Column

@Column注解用于指定实体类的属性与数据库表的列的映射关系。可以指定列名、是否可更新、是否可插入、是否可查询等属性。

3.4 @IdClass

当实体类中有多个主键属性时,可以使用@IdClass注解将主键属性组合成一个复合主键。需要实现一个包含所有主键属性的类,并重写hashCode()equals()方法。

4. JPA操作数据库的常用方法

4.1 createNativeQuery()

createNativeQuery()方法用于创建一个原生SQL查询,返回一个Query对象。可以调用getResultList()方法获取查询结果列表。

4.2 createNamedQuery()

createNamedQuery()方法用于创建一个命名查询,返回一个Query对象。命名查询使用带有命名空间前缀的全限定名进行查询,例如:SELECT u FROM User u WHERE u.username = :username AND u.password = :password。可以通过调用getSingleResult()方法获取单个查询结果,或者调用getResultList()方法获取查询结果列表。

4.3 merge()

merge()方法用于将一个实体类的实例合并到另一个实体类的实例中。通常用于更新操作,将一个实体类的状态复制到另一个实体类中。需要注意的是,只有关联属性才会被复制,非关联属性会被忽略。

4.4 persist()/persistAll()/refresh()/merge()

这些方法都用于将实体类实例保存到数据库中。其中:

  • persist()方法用于保存一个实体类实例,如果实例已经存在于数据库中,则抛出异常;否则,将实例添加到数据库会话中。返回值为布尔值,表示实例是否成功保存。
  • persistAll()方法用于保存一个实体类列表,遍历列表并调用每个实例的persist()方法。返回值为布尔值,表示所有实例是否成功保存。
  • refresh()方法用于刷新一个实体类实例的状态到数据库中的最新记录。通常在更新操作后调用该方法。如果实例不存在于数据库中,则抛出异常。返回值为布尔值,表示实例状态是否成功刷新。
  • merge()方法用于合并两个实体类实例的状态。通常在更新操作前调用该方法。返回值为布尔值,表示实例状态是否成功合并。

5. JPA分页查询

在JPA中,实现分页查询主要有两种方式:基于JpaRepository接口的方法和使用Criteria查询的方式。

5.1. 基于JpaRepository接口的方法:

JpaRepository是Spring Data JPA提供的一种Repository接口,通过继承该接口,我们可以方便地实现基本的CRUD操作。在JPA中,我们可以通过在Repository接口中定义方法的命名规范来实现分页查询。

首先,定义一个继承JpaRepository接口的Repository接口:

@Repositorypublic interface UserRepository extends JpaRepository<User, Long> {
 Page<User> findAll(Pageable pageable);
}
  • 1
  • 2
  • 3

然后,在Service层中调用Repository接口中定义的方法进行分页查询:

@Service
public class UserService {

 @Autowired 
 private UserRepository userRepository;

 public Page<User> getUsers(int page, int size) {
 Pageable pageable = PageRequest.of(page, size);
 return userRepository.findAll(pageable);
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
5.2. 使用Criteria查询的方式:

Criteria查询是JPA提供的一种动态查询方式,通过Criteria查询可以方便地实现复杂的查询需求。在JPA中,我们可以使用Criteria查询来实现分页查询。

首先,定义一个Criteria查询:

@Repository
public class UserRepository {
	 @PersistenceContext 
	 private EntityManager entityManager;
	
	 public List<User> getUsers(int page, int size) {
	 CriteriaBuilder cb = entityManager.getCriteriaBuilder();
	 CriteriaQuery<User> query = cb.createQuery(User.class);
	 Root<User> root = query.from(User.class);
	 query.select(root);
	
	 TypedQuery<User> typedQuery = entityManager.createQuery(query);
	 typedQuery.setFirstResult(page * size);
	 typedQuery.setMaxResults(size);
	
	 return typedQuery.getResultList();
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在上述代码中,我们使用CriteriaBuilder来构建Criteria查询,设置查询的起始位置和查询的数量,然后执行查询并返回结果。

通过以上两种方式,我们可以方便地实现JPA的分页查询操作。在实际项目中,我们可以根据具体的需求选择合适的方式来实现分页查询。

二、SpringBoot整合JPA框架(hibernate实现)详解

1. 在pom.xml中引入相应的依赖:
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
2. 在application.yml中配置数据库连接信息:
  jpa:
    database: mysql
    generate-ddl: true
    open-in-view: true
    hibernate:
      ddl-auto: update
      naming:
        physical-strategy: cn.wine.ms.base.jpa.util.UnderscoreNameCustomizer
    show-sql: true
    database-platform:
    properties:
      hibernate:
        enable_lazy_load_no_trans: true
  datasource:
    url: jdbc:mysql://localhost:3306/uaa?createDatabaseIfNotExist=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: 
    password: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
3.创建一个实体类,例如User:
package cn.wine.uaa.auth.dao.po;

import cn.wine.uaa.ms.enums.permission.UserAreaType;
import cn.wine.uaa.sdk.enums.CommonStatus;
import cn.wine.ms.base.jpa.po.BaseEntityPKIncrement;
import cn.wine.uaa.sdk.enums.YesOrNoStatus;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import org.hibernate.annotations.Where;

@Getter
@Setter
@Entity
@Table(name = "auth_user")
public class User extends BaseEntityPKIncrement implements Serializable{

	private static final long serialVersionUID = -4877271072444358347L;

	/**
	 * 用户账号
	 */
	@Column(name = "username",length = 12, nullable = false)
	@NotNull(message = "用户账号不能为空")
	@NotBlank(message = "用户账号不能为空")
	private String userName;

    /**
     * 对应EHR中的工号
     */
	@Column(length = 20, unique = true)
    @Size(max = 20, message = "工号 最长20位")
	private String jobNumber;

	/**
	 * 密码
	 * before:, nullable = false
	 * after:删除了这个参数
	 */
	@Column(length = 200)
	private String password;

	/**
	 * 用户姓名
	 */
	@Column(length = 50, nullable = false)
	private String name;

	/**
	 * 联系电话
	 */
	@Column(length = 50)
	private String phone;

	/**
	 * email
	 */
	@Column(length = 100)
	private String email;

	/**
	 * imageUrl
	 */
	@Column(name = "image_url", length = 500)
	private String imageUrl;

	/**
	 * 所属公司
	 */
	@Column(length = 50)
	private String company;

	/**
	 * 所属部门
	 */
	@Column(length = 50)
	private String dept;

	/**
	 * 岗位
	 */
	@Column(length = 50)
	private String post;

	/**
	 * 状态
	 */
	@Column(length = 10, nullable = false)
	@Enumerated(EnumType.STRING)
	private CommonStatus status = CommonStatus.ENABLE;

	/**
	 * 所拥有的角色类型
	 */
	@JsonIgnore
	@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
	@JoinTable(name = "auth_user_role", joinColumns = {
			@JoinColumn(name = "userId", referencedColumnName = "id")}, inverseJoinColumns = {
			@JoinColumn(name = "roleId", referencedColumnName = "id")}, uniqueConstraints = {
			@UniqueConstraint(columnNames = {"userId", "roleId"})})
    @Where(clause = "status='ENABLE'")
	private List<Role> roles;

	/**
	 * 菜单
	 */
	@Transient
	private List<MenuGroup> menus;

	/**
	 * 创建者
	 */
	@Column(length = 50)
	private String createBy;

	/**
	 * 是否自行修改过密码
	 */
	@Column(length = 3)
	@Enumerated(EnumType.STRING)
	private YesOrNoStatus updatedPwd = YesOrNoStatus.NO;

	/**密码输入错误次数*/
	@Column
	private Integer pwdErrorTime = 0;

	/**密码锁定截止时间*/
	@Column
	private Date userLockedTime;

	/**最后登录时间*/
	@Column
	private Date lastLoginTime;

	@Column(columnDefinition = "varchar(30) comment '默认打印机'")
	private String printer;

	@Column(columnDefinition = "varchar(10) comment '是否登陆过系统(判断是否是第一次登陆)'")
	@Enumerated(EnumType.STRING)
	private YesOrNoStatus logind;

	@Column(columnDefinition = "varchar(30) comment '用户片区类型'")
	@Enumerated(EnumType.STRING)
	private UserAreaType userAreaType;

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
import java.io.Serializable;
import java.sql.Timestamp;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.hibernate.annotations.UpdateTimestamp;

@MappedSuperclass
@Getter
@Setter
public class BaseEntityPKIncrement  implements Serializable {
    @Id
    @Stringify
    @GeneratedValue(
        strategy = GenerationType.IDENTITY
    )
    private Long id;
    private Timestamp createTimestamp = new Timestamp(System.currentTimeMillis());
    @UpdateTimestamp
    private Timestamp updateTimestamp;

    public BaseEntityPKIncrement() {
    }

    public Long getId() {
        return this.id;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
4.创建一个Repository接口,用于操作数据库:
@Repository
public interface UserRepository extends JpaRepository<User, Long>, UserDao, JpaSpecificationExecutor<User> {}


public class UserRepositoryImpl extends CommonJpaRepositoryBean<User, String> implements UserDao {

    @Autowired
    public UserRepositoryImpl(EntityManager em) {
        super(User.class, em);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
5.在Controller中进行增删改查操作:
@Service // 标注为服务类
public class UserService {
    @Autowired // 自动装配UserRepository
    private UserRepository userRepository;
    
    // 添加用户
    public void addUser(String username) {
        User newUser = new User();
        newUser.setUsername(username);
        
        userRepository.save(newUser);
    }
    
    // 根据ID获取用户信息
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    // 更新用户信息
    public void updateUser(Long id, String newName) {
        User existingUser = userRepository.getOne(id);
        if (existingUser != null) {
            existingUser.setUsername(newName);
            
            userRepository.save(existingUser);
        } else {
            throw new IllegalArgumentException("Invalid user ID");
        }
    }
    
    // 删除用户
    public void deleteUser(Long id) {
        User existingUser = userRepository.getOne(id);
        if (existingUser != null) {
            userRepository.delete(existingUser);
        } else {
            throw new IllegalArgumentException("Invalid user ID");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

这样,我们就完成了一个简单的Spring Boot项目,整合了JPA和Hibernate,实现了对User实体类的增删改查操作。可以通过访问/users来查看所有用户,通过POST请求向/users创建新用户,通过PUT请求/users/{id}来更新用户,通过DELETE请求/users/{id}来删除用户。 希望可以帮助到你学习Spring Boot整合JPA和Hibernate。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/815252
推荐阅读
相关标签
  

闽ICP备14008679号