简介
JPA是ORM框架(对象关系映射,面向对象的思想来处理数据库操作)的一套规范,它只提供接口,实现过程要其他框架进行实现。
JPA(JAVA Persistence API)是Sun官方提出的Java持久化规范,用来方便大家操作数据库,真正干活的是Hibernate,TopLink等实现了JPA规范的框架,默认是Hibernate。
springboot的jpa
添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> |
配置
application.properties文件中添加配置
spring.data.jpa.repositories.enabled=true |
spring.jpa.show-sql设置为true表示控制台显示sql
常用注解
@Entity //告诉JPA这是一个实体类(和数据表映射的类)
@Table来指定和哪个数据表对应;
@Id //这是一个主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
@Column(name = "last_name",length = 50) //这是和数据表对应的一个列,括号不写默认和属性名一样
@Query(value=" 这里就是查询语句")
@Query支持hql和原生sql两种方式,默认是hql ,hql就是语句中用的是实体名字和实体属性,原生sql用的表名字和表字段
@Query("select u from User u where u.emailAddress = ?1") User findByEmailAddress(String emailAddress); @Modifying @Transactional @Query("update CardConfig set cardStatus=?1 where id in ?2") void updateCardStatus( Integer status,List<Integer> listIds); / @Param 代替参数占位符, hql或者sql里就用 :firstname替换方法里的参数顺序可以打乱 @Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname") User findByLastnameOrFirstname(@Param("lastname") String lastname, @Param("firstname") String firstname); //返回字段 组成新的entity返回 类名必须是全写的 @Query(value="select new com.hikvision.metro.modules.repository.entity.CameraIndexs(c.preOneCameraIndexcode, c.preTwoCameraIndexcode, c.backOneCameraIndexcode) from StationDeviceConfig c") List<CameraIndexs> getAllCameraIndexs();
|
语句可以直接放到数据库中执行 nativeQuery=true Modifying @Query(value="select status from t_station_device_config where pre_one_camera_indexcode=?1",nativeQuery = true) List<Integer> findStatusByPreOneCameraIndexcode(String index);
|
@EnableJpaRepositories
在Springboot应用开发中使用JPA时,通常在主应用程序所在包或者其子包的某个位置定义我们的Entity和Repository,这样基于Springboot的自动配置,无需额外配置,我们定义的Entity和Repository即可被发现和使用。但有时候我们需要定义Entity和Repository不在应用程序所在包及其子包,那么这时候就需要使用@EntityScan和@EnableJpaRepositories了。
@EntityScan用来扫描和发现指定包及其子包中的Entity定义。其用法如下:
@EntityScan(basePackages = {"com.department.entities","come.employee.entities"})
如果多处使用@EntityScan,它们的basePackages集合能覆盖所有被Repository使用的Entity即可,集合有交集也没有关系。但是如果不能覆盖被Repository使用的Entity,应用程序启动是会出错,比如:
Not a managed type: com.customer.entities.Customer
@EnableJpaRepositories
@EnableJpaRepositories用来扫描和发现指定包及其子包中的Repository定义。其用法如下:
@EnableJpaRepositories(basePackages = {"com.department.repositories","come.employee.repositories"})
如果多处使用@EnableJpaRepositories,它们的basePackages集合不能有交集,并且要能覆盖所有需要的Repository定义。
如果有交集,相应的Repository会被尝试反复注册,从而遇到如下错误:
The bean ‘OrderRepository’, defined in xxx, could not be registered. A bean with that name has already been defined in xxx and overriding is disabled.
如果不能覆盖所有需要的Repository定义,会遇到启动错误:
Parameter 0 of method setCustomerRepository in com.service.CustomerService required a bean of type ‘come.repo.OrderRepository’ that could not be found.
关键字
实例
实体类
import javax.persistence.*;
@Entity @Table(name="t_users") public class Users {
@Id //主键id @GeneratedValue(strategy=GenerationType.IDENTITY)//主键生成策略 @Column(name="id")//数据库字段名 private Integer id;
@Column(name="name") private String name;
@Column(name="age") private Integer age;
@Column(name="address") private String address;
@ManyToOne(cascade = CascadeType.PERSIST) //表示多方 @JoinColumn(name ="role_id") //维护一个外键,外键在Users一侧 private Roles roles;
public Roles getRoles() { return roles; }
public void setRoles(Roles roles) { this.roles = roles; }
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } |
DAO接口
import org.springframework.data.jpa.repository.JpaRepository;
import com.bjsxt.pojo.Users; /** * 参数一 T :当前需要映射的实体 * 参数二 ID :当前映射的实体中的OID的类型 * */ public interface UsersRepository extends JpaRepository<Users,Integer> {
} |
JpaRepository 这个父接口,提供了CRUD, 分页等等一系列的查询,在项目中直接拿来用,不需要二次开发。在开发中我们并不需要写SQL语句
接口说明:
SpringBoot JPA提供的核心接口
1、Repository接口
2、CrudRepository接口
3、PagingAndSortingRepository接口
4、JpaRepository接口
5、JPASpecificationExecutor接口
Repository接口的使用
提供了方法名称命名查询方式
提供了基于@Query注解查询与更新
- dao层接口(方法名称命名查询方式)
public interface UsersRepositoryByName extends Repository<Users,Integer> { //方法名称必须要遵循驼峰式命名规则,findBy(关键字)+属性名称(首字母大写)+查询条件(首字母大写) List<Users> findByName(String name);
List<Users> findByNameAndAge(String name,Integer age);
List<Users> findByNameLike(String name);
} |
于@Query注解查询与更新
public interface UsersRepositoryQueryAnnotation extends JpaRepository<Users,Integer> { @Query("from Users where name = ?") List<Users> queryByNameUseHQL(String name);
@Query(value = "select * from t_user where name=?",nativeQuery = true) List<Users> queryByNameUseSQL(String name);
@Query("update Users set name=? where id=?") @Modifying //需要执行一个更新操作 void updateUsersNameById(String name,Integer id);
} |
CrudRepository接口的使用
CrudRepository接口,主要是完成一些增删改查的操作。注意:CrudRepository接口继承了Repository接口
public interface UsersRepositoryCrudRepository extends CrudRepository<Users,Integer> { } |
@Test public void testCrudRepositorySave() { Users users=new Users(); users.setName("青衫"); users.setAge(30); users.setAddress("湖南怀化"); this.usersRepositoryCrudRepository.save(users); }
@Test public void testCrudRepositoryUpdate() { Users users=new Users(); users.setId(4); users.setName("青"); users.setAge(18); users.setAddress("怀化"); this.usersRepositoryCrudRepository.save(users); }
@Test public void testCrudRepositoryFindOne() {
Users users=this.usersRepositoryCrudRepository.findOne(4); System.out.println(users); }
@Test public void testCrudRepositoryFindAll() { List<Users> list= (List<Users>) this.usersRepositoryCrudRepository.findAll(); for (Users user:list){ System.out.println(user); } }
@Test public void testCrudRepositoryDeleteById() { this.usersRepositoryCrudRepository.delete(4);
} |
PagingAndSortingRepository接口的使用
该接口提供了分页与排序的操作,注意:该接口继承了CrudRepository接口
public interface UsersRepositoryPagingAndSorting extends PagingAndSortingRepository<Users,Integer> { } |
//Order 定义了排序规则 Sort.Order order=new Sort.Order(Sort.Direction.DESC,"id"); //Sort对象封装了排序规则 Sort sort=new Sort(order); List<Users> list= (List<Users>) this.usersRepositoryPagingAndSorting.findAll(sort); //Pageable:封装了分页的参数,当前页,煤业显示的条数。注意:它的当前页是从0开始 //PageRequest(page,size):page表示当前页,size表示每页显示多少条 Pageable pageable=new PageRequest(1,2); Page<Users> page=this.usersRepositoryPagingAndSorting.findAll(pageable);
Sort sort=new Sort(new Sort.Order(Sort.Direction.DESC,"id")); Pageable pageable=new PageRequest(0,2,sort); Page<Users> page=this.usersRepositoryPagingAndSorting.findAll(pageable);
|
JpaRepository接口
该接口继承了PagingAndSortingRepository。对继承的父接口中方法的返回值进行适配。
public interface UsersRepository extends JpaRepository<Users,Integer> {
} |
JPASpecificationExecutor接口
该接口主要是提供了多条件查询的支持,并且可以在查询中添加排序与分页。注意JPASpecificationExecutor是单独存在的。完全独立
public interface UserRepositorySpecification extends JpaRepository<Users,Integer>,JpaSpecificationExecutor<Users> { } |
@Test public void testJpaSpecificationExecutor1() { /** * Specification:用于封装查查询条件 */ Specification<Users> spec=new Specification<Users>() { //Predicate:封装了单个查询条件
/** * @param root 对查询对象属性的封装 * @param criteriaQuery 封装了我们要执行的查询中的各个部分的信息,select from order * @param criteriaBuilder 查询条件的构造器 * @return */ @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { //where name="张三" /** * 参数一:查询的属性 * 参数二:条件的值 */ Predicate predicate=criteriaBuilder.equal(root.get("name"),"张三"); return predicate; } }; List<Users> list=this.userRepositorySpecification.findAll(spec); for (Users users:list){ System.out.println(users); } }
/** * JpaSpecificationExecutor 多条件查询方式一 */ @Test public void testJpaSpecificationExecutor2() { /** * Specification:用于封装查查询条件 */ Specification<Users> spec=new Specification<Users>() { //Predicate:封装了单个查询条件
/** * @param root 对查询对象属性的封装 * @param criteriaQuery 封装了我们要执行的查询中的各个部分的信息,select from order * @param criteriaBuilder 查询条件的构造器 * @return */ @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { //where name="张三" and age=20 /** * 参数一:查询的属性 * 参数二:条件的值 */ List<Predicate> list=new ArrayList<>(); list.add(criteriaBuilder.equal(root.get("name"),"张三")); list.add(criteriaBuilder.equal(root.get("age"),20)); Predicate[] arr=new Predicate[list.size()]; return criteriaBuilder.and(list.toArray(arr)); } }; List<Users> list=this.userRepositorySpecification.findAll(spec); for (Users users:list){ System.out.println(users); } }
/** * JpaSpecificationExecutor 多条件查询方式二 */ @Test public void testJpaSpecificationExecutor3() { /** * Specification:用于封装查查询条件 */ Specification<Users> spec=new Specification<Users>() { //Predicate:封装了单个查询条件
/** * @param root 对查询对象属性的封装 * @param criteriaQuery 封装了我们要执行的查询中的各个部分的信息,select from order * @param criteriaBuilder 查询条件的构造器 * @return */ @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { //where name="张三" and age=20 /** * 参数一:查询的属性 * 参数二:条件的值 */ /*List<Predicate> list=new ArrayList<>(); list.add(criteriaBuilder.equal(root.get("name"),"张三")); list.add(criteriaBuilder.equal(root.get("age"),20)); Predicate[] arr=new Predicate[list.size()];*/ //(name='张三' and age=20) or id=2 return criteriaBuilder.or(criteriaBuilder.and(criteriaBuilder.equal(root.get("name"),"张三"),criteriaBuilder.equal(root.get("age"),20)),criteriaBuilder.equal(root.get("id"),1)); } };
Sort sort=new Sort(new Sort.Order(Sort.Direction.DESC,"id")); List<Users> list=this.userRepositorySpecification.findAll(spec,sort); for (Users users:list){ System.out.println(users); } } |
其他总结
Specification