JAP的由来
ORM框架能够将Java对象映射到关系型数据库中,能够直接持久化复杂的Java对象。ORM的出现让开发者从数据库编程中解脱出来,把更多的精力放在业务模型与业务逻辑,目前流行的ORM框架有MyBatis,Hibernate,JDO等。
JPA是什么?
JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据,它的出现简化现有的持久化开发工作和整合ORM技术,结束了MyBatis,Hibernate,JDO各自经营的局面。
JPA充分吸收了现有的MyBatis,Hibernate,JDO等ORM框架的基础上发展而来的,易于使用,伸缩性强等优点。
注意:
JPA是一套规范,不是一套产品,MyBatis,Hibernate,JDO框架是一套产品,如果这些产品实现了JPA规范,那么我们称它们为JPA的实现产品
JPA=Java Persistence APIJava持久化API
MyBatis,Hibernate,JDO 框架都是一种实现。
Spring Data JPA
Spring Data是Spring的一个子项目,用于简化数据库访问,NoSQL非关系型数据库,还包括对关系型数据库的访问之处,所有数据库访问都要通过Spring Data,Spring Data让数据库访问变的更加方便
Spring Data JPA让我们解脱了DAO层的操作,基本上所有CRUD(增删改查)都可以依赖于它的实现。
配置数据源-配置JPA相关信息
#配置数据源相关信息
#MYSQL5.x版本的驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/crm?useUnicode=true&&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
#配置JPA(Hibernate)相关信息
#spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
hibernate.hbm2ddl.auto参数的作用主要用于:创建、更新、验证数据库表结构
create:
如果设置为该值,则每次加载hibernate时(准确说应是创建SessionFactory时)都会删除以前创建的表而根据model重新生成表,即使前后的表没有任何变化,通常会造成数据库数据丢失,需谨慎使用这个取值
create-drop:
与create差不多,所不同的是每次sessionFactory关闭时,就会删除所有表
update:
这个取值比较常用,需要先建立数据库,在第一次加载hibernate时会自动创建表,以后创建hibernate会自动根据model更新表结构,即使表结构改变了,以前的行不会被删除
validate:
每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值
hibernate.dialect:
主要是指定数据库方言(数据库类型)
show-sql:
是否在日志中打印出自动生成的SQL,方便调试的时候查看
format_sql:
是否格式化SQL
IDEA连接Mysql数据库
第一步创建实体类
创建User.java实体类
package com.li.jap.model;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "sys_user")
@NamedQueries(@NamedQuery(name = "User.findUsersByName",query = "select u from User u where u.usrName=:usrname"))
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "usr_id")
private Long usrId;
@Column(name = "usr_name")
private String usrName;
@Column(name = "usr_password")
private String usrPassword;
@Column(name = "usr_role_id")
private Long usrRoleId;
@Column(name = "usr_flag")
private Integer usrFlag;
@Entity 表明该类 (UserEntity) 为一个被JPA管理的实体类,它默认对应数据库中的表名是sys_user。
@Table: 当实体类与其映射的数据库表名不同名时需要使用 @Table注解说明,该标注与 @Entity 注解并列使用,置于实体类声明语句之前,可写于单独语句行,也可与声明语句同行。
@Column:当实体的属性与其映射的数据库表的列不同名时需要使用@Column 标注说明,该属性通常置于实体的属性声明语句之前(置于属性的getter方法之前),还可与 @Id 标注一起使用。
@Id: 标注用于声明一个实体类的属性映射为数据库的主键列。该属性通常置于属性声明语句之前,可与声明语句同行,也可写在单独行上,但一个实体类里面必须有一个。 @Id标注也可置于属性的getter方法之前。
@GeneratedValue:主要就是为一个实体生成一个唯一标识的主键、@GeneratedValue提供了主键的生成策略。
@Transient并非一个到数据库表的字段的映射,表示非持久化属性
@Enumerated直接映射enum 枚举类型的字段点击查看详情
第二步编写Repository
public interface UserRepository extends JpaRepository<User,Long> , JpaSpecificationExecutor<User> {
}
JpaRepository继承PagingAndSortingRepository和QueryByExampleExecutor。
PagingAndSortingRepository类主要负责排序和分页内容。
QueryByExampleExecutor类提供了很多示例的查询方法。
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
}
继承JpaRepository的Repository会自动用于示例的查询方法和排序、分页功能。
PagingAndSortingRepository又继承了CrudRepository
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
}
CrudRepository内置了增、删、改、查的方法。
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
/**
* Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
* entity instance completely.
*
* @param entity must not be {@literal null}.
* @return the saved entity; will never be {@literal null}.
* @throws IllegalArgumentException in case the given {@literal entity} is {@literal null}.
*/
<S extends T> S save(S entity);
/**
* Saves all given entities.
*
* @param entities must not be {@literal null} nor must it contain {@literal null}.
* @return the saved entities; will never be {@literal null}. The returned {@literal Iterable} will have the same size
* as the {@literal Iterable} passed as an argument.
* @throws IllegalArgumentException in case the given {@link Iterable entities} or one of its entities is
* {@literal null}.
*/
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
/**
* Retrieves an entity by its id.
*
* @param id must not be {@literal null}.
* @return the entity with the given id or {@literal Optional#empty()} if none found.
* @throws IllegalArgumentException if {@literal id} is {@literal null}.
*/
Optional<T> findById(ID id);
/**
* Returns whether an entity with the given id exists.
*
* @param id must not be {@literal null}.
* @return {@literal true} if an entity with the given id exists, {@literal false} otherwise.
* @throws IllegalArgumentException if {@literal id} is {@literal null}.
*/
boolean existsById(ID id);
/**
* Returns all instances of the type.
*
* @return all entities
*/
Iterable<T> findAll();
/**
* Returns all instances of the type {@code T} with the given IDs.
* <p>
* If some or all ids are not found, no entities are returned for these IDs.
* <p>
* Note that the order of elements in the result is not guaranteed.
*
* @param ids must not be {@literal null} nor contain any {@literal null} values.
* @return guaranteed to be not {@literal null}. The size can be equal or less than the number of given
* {@literal ids}.
* @throws IllegalArgumentException in case the given {@link Iterable ids} or one of its items is {@literal null}.
*/
Iterable<T> findAllById(Iterable<ID> ids);
/**
* Returns the number of entities available.
*
* @return the number of entities.
*/
long count();
/**
* Deletes the entity with the given id.
*
* @param id must not be {@literal null}.
* @throws IllegalArgumentException in case the given {@literal id} is {@literal null}
*/
void deleteById(ID id);
/**
* Deletes a given entity.
*
* @param entity must not be {@literal null}.
* @throws IllegalArgumentException in case the given entity is {@literal null}.
*/
void delete(T entity);
/**
* Deletes the given entities.
*
* @param entities must not be {@literal null}. Must not contain {@literal null} elements.
* @throws IllegalArgumentException in case the given {@literal entities} or one of its entities is {@literal null}.
*/
void deleteAll(Iterable<? extends T> entities);
/**
* Deletes all entities managed by the repository.
*/
void deleteAll();
}
JpaRepository继承了PagingAndSortingRepository,PagingAndSortingRepository又继承了CrudRepository,所以JpaRepository默认拥有上述方法。
第三步测试用例
@RunWith(SpringRunner.class)
@SpringBootTest
class JapApplicationTests {
@Resource
private UserRepository userRepository;
@Test
void contextLoads() {
User user = new User("JPA","123456",8L,1);
userRepository.save(user);
}
@Test
public void testGet(){
User user = userRepository.findById(1L).get();
System.out.printf("usrName"+user.getUsrName());
}
}
复杂操作
自定义QL查询
模糊查询
//模糊查询
public List<User> findByUsrNameLike(String usrName);
使用自定义QL查询 维护可读性。
//使用自定义QL查询 维护可读性。
@Query("select u from User u where u.usrRoleId=:roleId")
public User findByRoleId(@Param("roleId") Long roleId);
修改删除操作
//修改删除操作
@Transactional(timeout = 10) //对事务的支持,操作超时设置
@Modifying
@Query("update User u set u.usrName=:usrname where u.usrId=:usrid")
public int modifyNameById(@Param("usrname")String usrname,
@Param("usrid") Long usrid);
命名QL查询
在实体类上添加@NamedQueries注解
@NamedQueries(@NamedQuery(name = "User.findUsersByName",query = "select u from User u where u.usrName=:usrname"))
分页查询
Pageable 是Spring封装的分页实现类,使用的时候需要传入页数,每页条数和排序规则。
Page是Spring封装的分页对象,封装了总页数,分页数据等,返回对象除了使用Page外,还可以使用Slice作为返回值。
@Query("select u from User u where u.usrRoleId=:roleId")
public Page<User> findPageByUsrRoleId(@Param("roleId") Long roleId, Pageable pageable);
Page和Slice的区别如下:
- Page接口继承自Slice接口,而Slice继承自Iterable接口。
- Page接口扩展了Slice接口,添加了获取总页数和元素总数量的方法,因此返回Page接口时,必须执行两条SQL,一条查询分页数据,一条负责查询总数量
- 返回Slice结果时,查询的SQL只会有查询分页数据这一条,不统计数据数量。
- 值得注意的是,Page实现了获取所有记录的数量和页面的总数,但是它是通过count query来计算的,所以当数据源大的时候,就会显示出劣势;但是Slice在做某些操作的时候并不需要把所有的记录数都计算一次!
@Test
public void testFindPageByUsrRoleId(){
int page = 0,size=2; //分页要素,页数从0开始
//控制分页数据的排序,可以选择升序和降序
Sort sort= Sort.by(Sort.Direction.DESC,"usrId");
//控制分页的辅助类,可以设置页码,每页的数据条数,排序等
Pageable pageable = PageRequest.of(page,size,sort);
Page<User> userPage = userRepository.findPageByUsrRoleId(8L,pageable);
System.out.println("总记录数:"+userPage.getTotalElements());
System.out.println("总页数:"+userPage.getTotalPages());
System.out.println("当前页数:"+(userPage.getNumber()+1));
System.out.println("每页记录数:"+userPage.getSize());
System.out.println("当前页记录数:"+userPage.getNumberOfElements());
for (User user : userPage.getContent()){//获得查询的数据
System.out.println("usrId:"+user.getUsrName());
}
}