Java Persistence API(JPA)是Java EE和Java SE平台的一部分,提供了一种简单的对象关系映射(ORM)机制,用于将Java对象持久化到关系型数据库中。JPA通过注解或XML配置文件实现实体类与数据库表之间的映射,简化了数据库操作的过程。
EntityManagerFactory是JPA的核心接口,用于创建EntityManager实例。通常在一个应用程序中只创建一个EntityManagerFactory实例,并通过单例模式或者池化管理。
EntityManager是JPA的核心接口,用于执行数据库操作,如插入、更新、删除和查询。每个线程只能有一个EntityManager实例。
EntityTransaction是一个事务对象,用于定义一组操作的原子性。事务具有以下四个属性:隔离级别、传播行为、超时时间和只读属性。
@Entity注解用于标记一个类为实体类,表示该类将被持久化到数据库中。通常需要为主键字段添加@Id注解,其他属性使用@Column注解进行映射。
@Table注解用于指定实体类对应的数据库表名。如果需要指定多个表名,可以使用@Table(name = "table_name")的方式。
@Column注解用于指定实体类的属性与数据库表的列的映射关系。可以指定列名、是否可更新、是否可插入、是否可查询等属性。
当实体类中有多个主键属性时,可以使用@IdClass注解将主键属性组合成一个复合主键。需要实现一个包含所有主键属性的类,并重写hashCode()和equals()方法。
createNativeQuery()方法用于创建一个原生SQL查询,返回一个Query对象。可以调用getResultList()方法获取查询结果列表。
createNamedQuery()方法用于创建一个命名查询,返回一个Query对象。命名查询使用带有命名空间前缀的全限定名进行查询,例如:SELECT u FROM User u WHERE u.username = :username AND u.password = :password。可以通过调用getSingleResult()方法获取单个查询结果,或者调用getResultList()方法获取查询结果列表。
merge()方法用于将一个实体类的实例合并到另一个实体类的实例中。通常用于更新操作,将一个实体类的状态复制到另一个实体类中。需要注意的是,只有关联属性才会被复制,非关联属性会被忽略。
这些方法都用于将实体类实例保存到数据库中。其中:
在JPA中,实现分页查询主要有两种方式:基于JpaRepository接口的方法和使用Criteria查询的方式。
JpaRepository是Spring Data JPA提供的一种Repository接口,通过继承该接口,我们可以方便地实现基本的CRUD操作。在JPA中,我们可以通过在Repository接口中定义方法的命名规范来实现分页查询。
首先,定义一个继承JpaRepository接口的Repository接口:
@Repositorypublic interface UserRepository extends JpaRepository{ Page findAll(Pageable pageable); }
然后,在Service层中调用Repository接口中定义的方法进行分页查询:
@Service public class UserService { @Autowired private UserRepository userRepository; public PagegetUsers(int page, int size) { Pageable pageable = PageRequest.of(page, size); return userRepository.findAll(pageable); } }
Criteria查询是JPA提供的一种动态查询方式,通过Criteria查询可以方便地实现复杂的查询需求。在JPA中,我们可以使用Criteria查询来实现分页查询。
首先,定义一个Criteria查询:
@Repository public class UserRepository { @PersistenceContext private EntityManager entityManager; public ListgetUsers(int page, int size) { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery query = cb.createQuery(User.class); Root root = query.from(User.class); query.select(root); TypedQuery typedQuery = entityManager.createQuery(query); typedQuery.setFirstResult(page * size); typedQuery.setMaxResults(size); return typedQuery.getResultList(); } }
在上述代码中,我们使用CriteriaBuilder来构建Criteria查询,设置查询的起始位置和查询的数量,然后执行查询并返回结果。
通过以上两种方式,我们可以方便地实现JPA的分页查询操作。在实际项目中,我们可以根据具体的需求选择合适的方式来实现分页查询。
org.springframework.boot spring-boot-starter-data-jpaorg.hibernate hibernate-jpamodelgen
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:
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 Listroles; /** * 菜单 */ @Transient private List 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; } }
@Repository public interface UserRepository extends JpaRepository, UserDao, JpaSpecificationExecutor {} public class UserRepositoryImpl extends CommonJpaRepositoryBean implements UserDao { @Autowired public UserRepositoryImpl(EntityManager em) { super(User.class, em); }
@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。