一、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);
}
然后,在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);
}
}
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();
}
}
在上述代码中,我们使用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>
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:
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;
}
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;
}
}
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);
}
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");
}
}
}
这样,我们就完成了一个简单的Spring Boot项目,整合了JPA和Hibernate,实现了对User实体类的增删改查操作。可以通过访问
/users
来查看所有用户,通过
POST
请求向
/users
创建新用户,通过
PUT
请求
/users/{id}
来更新用户,通过
DELETE
请求
/users/{id}
来删除用户。 希望可以帮助到你学习Spring Boot整合JPA和Hibernate。
版权归原作者 浪打白龙 所有, 如有侵权,请联系我们删除。