Spring Data JPA 学习
Spring Data JPA是个非常强大的ORM持久化解决方案,免去了mybatis或spring jdbcTemplate的开发人员编写脚本的无趣工作。
Spring Data JPA官方文档
https://docs.spring.io/spring-data/jpa/docs/2.0.9.RELEASE/reference/html/
一、首先了解下Spring Data JPA 的继承结构
Repository:标识接口
CrudRepository:用于CRUD操作(修改的方法和添加一样都是save,至于什么时候是修改,什么时候是添加后面会说)
PagingAndSortingRepository:用于分页和排序操作
JpaRepository:将其他接口的方法的返回值做适配处理
除了图中的内容,还必须掌握JpaSpecificationExecutor,该接口不在图中的关系中,起作用是多条件查询且支持分页和查询。
如果说有什么关系,请看下图
二、首先了解下Spring Data JPA 的运行原理(简单说下)
我们知道使用Spring Data JPA是不需要接口实现类的,但我们在测试类中自动注入的UsersDao到底是什么呢?
UsersDao接口
package com.zxw.dao;
import com.zxw.pojo.Users;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UsersDao extends JpaRepository<Users,Integer> {
}
测试类
package com.zxw.test;
import com.zxw.dao.UsersDao;
import com.zxw.pojo.Users;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UsersDaoImplTest {
@Autowired
private UsersDao usersDao;
@Test
public void test() {
System.out.println(usersDao);
System.out.println(usersDao.getClass());
}
}
我们通过简单输出看下UserDao到底是什么
从结果可以看出usersDao的类型是个代理类,usersDao是个SimpleJpaRepository对象。
我们看看SimpleJpaRepository是何方神圣?
可以看到SimpleJpaRepository实现了JpaRepository,JpaSpecificationExecutor接口,再看看有什么方法
这里只截取一部分,可以看出SimpleJpaRepository实现了相应的CURD操作。
其实我们自己也可以产生个代理对象:
@PersistenceContext(name="entityManagerFactory")
private EntityManager em;
@Test
public void test1(){
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
//getRepository(UsersDao.class);可以帮助我们为接口生成实现类。而这个实现类是 SimpleJpaRepository 的对象
// 要求:该接口必须要是继承 Repository 接口
UsersDao ud = factory.getRepository(UsersDao.class);
System.out.println(ud);
System.out.println(ud.getClass());
}
三、Repository接口
Repository接口是Spring Data JPA 中提供的所有接口的顶层接口
Repository提供了两种查询方式:
- 基于方法名称命名规则查询
- 基于@Query注解查询
方法名称命名规则查询
public interface UsersDao extends Repository<Users,Integer> {
//findBy关键字 Username属性名称 Is查询条件
List<Users> findByUsernameIs(String username);
}
@Query注解查询
- 通过JPQL语句查询
JPQL:通过 Hibernate 的 HQL 演变过来的。他和 HQL 语法及其相似。
public interface UsersDao extends Repository<Users,Integer> {
//JPQL
@Query("from Users where username like ?")
List<Users> selByLikeName(String username);
@Query("from Users where userage > ?")
List<Users> selByAge(Integer userage);
@Query("from Users where username = ? and userage <= ?")
List<Users> selNameAndAge(String username,Integer userage);
}
- 通过SQL语句查询
(前面没有写nativeQuery是因为我们所写的语句需要变成可以查询的sql语句,这里我们写的本身就是sql语句所以要开启nativeQuery)
public interface UsersDao extends Repository<Users,Integer> {
//SQL
//nativeQuery:默认的是 false.表示不开启 sql 查询。是否对 value 中的语句 做转义。
@Query(value = "select * from t_users where username like ?",nativeQuery = true)
List<Users> selByLikeNameSQL(String username);
@Query(value = "select * from t_users where userage > ?",nativeQuery = true)
List<Users> selByAgeSQL(Integer userage);
@Query(value = "select * from t_users where username = ? and userage <=?",nativeQuery = true)
List<Users> selNameAndAgeSQL(String username,Integer userage);
}
@Query注解完成修改
(一定要写@Modifying)
public interface UsersDao extends Repository<Users,Integer> {
//修改
@Query("update Users set userage = ? where userid = ?")
@Modifying //代表这是更新
void updUserageById(Integer userage,Integer userid);
}
四、CrudRepository接口
package com.zxw.dao;
import com.zxw.pojo.Users;
import org.springframework.data.repository.CrudRepository;
public interface UsersDao extends CrudRepository<Users,Integer> {
}
测试代码
package com.zxw.test;
import com.zxw.dao.UsersDao;
import com.zxw.pojo.Users;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UsersDaoImplTest {
@Autowired
private UsersDao usersDao;
/**
* 插入单条数据
*/
@Test
public void save(){
Users users=new Users();
users.setUsername("金泰妍");
users.setUserage(20);
this.usersDao.save(users);
}
/**
* 插入多条数据
*/
@Test
public void saveMany(){
Users users1=new Users();
users1.setUsername("林允儿");
users1.setUserage(30);
Users users2=new Users();
users2.setUsername("徐珠贤");
users2.setUserage(25);
List<Users> list=new ArrayList<>();
list.add(users1);
list.add(users2);
this.usersDao.save(list);
}
/**
* 查询所有
*/
@Test
public void findAll(){
List<Users> all = (List<Users>) this.usersDao.findAll();
for (Users u:all) {
System.out.println(u);
}
}
/**
* 查询单个
*/
@Test
public void findOne(){
Users one = this.usersDao.findOne(3);
System.out.println(one);
}
/**
* 修改 方式一
*/
@Test
public void updOne(){
Users one = this.usersDao.findOne(3);
one.setUsername("Vivian");
this.usersDao.save(one);
}
/**
* 修改 方式二 事务依赖本方法
*/
@Test
@Transactional
@Rollback(false)
public void updTwo(){
Users one = this.usersDao.findOne(3);//持久化
one.setUsername("Snow");
}
/**
* 删除
*/
@Test
public void del(){
this.usersDao.delete(8);
}
}
五、PagingAndSortingRepository接口
package com.zxw.dao;
import com.zxw.pojo.Users;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface UsersDao extends PagingAndSortingRepository<Users,Integer> {
}
测试类
package com.zxw.test;
import com.zxw.dao.UsersDao;
import com.zxw.pojo.Users;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UsersDaoImplTest {
@Autowired
private UsersDao usersDao;
/**
* 分页
*/
@Test
public void page(){
int page=0;//页数索引 从0开始
int size=2;//一页几条数据
//分页
Pageable pageable=new PageRequest(page,size);
Page<Users> usersPage = this.usersDao.findAll(pageable);
System.out.println("总条数:"+usersPage.getTotalElements());
System.out.println("总页数:"+usersPage.getTotalPages());
List<Users> users = usersPage.getContent();
for (Users u:users) {
System.out.println(u);
}
}
/**
* 分页+排序
*/
@Test
public void pageAndSort(){
int page=0;//页数索引 从0开始
int size=2;//一页几条数据
//排序
Sort sort=new Sort(Sort.Direction.DESC,"userage");
//分页
Pageable pageable=new PageRequest(page,size,sort);
Page<Users> usersPage = this.usersDao.findAll(pageable);
System.out.println("总条数:"+usersPage.getTotalElements());
System.out.println("总页数:"+usersPage.getTotalPages());
List<Users> users = usersPage.getContent();
for (Users u:users) {
System.out.println(u);
}
}
/**
* 排序 单条件
*/
@Test
public void sortTest(){
//Sort:该对象封装了排序规则以及指定的排序字段(对象的属性来表示)
// direction:排序规则
// properties:指定做排序的属性
Sort sort = new Sort(Sort.Direction.DESC,"userage");
List<Users> list = (List<Users>)this.usersDao.findAll(sort);
for (Users users : list) {
System.out.println(users);
}
}
/**
* 排序 多条件
*/
@Test
public void sort2Test(){
//Sort:该对象封装了排序规则以及指定的排序字段(对象的属性来表示)
// direction:排序规则
// properties:指定做排序的属性
//多条件查询时使用,一个order代表一个条件
Sort.Order order=new Sort.Order(Sort.Direction.DESC,"userage");
Sort.Order order1=new Sort.Order(Sort.Direction.ASC,"username");
Sort sort = new Sort(order,order1);
List<Users> list = (List<Users>)this.usersDao.findAll(sort);
for (Users users : list) {
System.out.println(users);
}
}
}
六、JpaRepository接口
package com.zxw.dao;
import com.zxw.pojo.Users;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UsersDao extends JpaRepository<Users,Integer> {
}
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UsersDaoImplTest {
@Autowired
private UsersDao usersDao;
/*** 添加用户 */
@Test
@Transactional
// 在测试类对于事务提交方式默认的是回滚。
@Rollback(false)//取消自动回滚
public void testInsertUsers() {
Users users = new Users();
users.setUserage(18);
users.setUsername("凑崎纱夏");
this.usersDao.save(users);
}
}
七、JpaSpecificationExecutor接口
package com.zxw.dao;
import com.zxw.pojo.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
/**
* JpaSpecificationExecutor不能单独使用
*/
public interface UsersDao extends JpaRepository<Users,Integer>, JpaSpecificationExecutor<Users> {
}
测试类
package com.zxw.test;
import com.zxw.dao.UsersDao;
import com.zxw.pojo.Users;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.sound.midi.Soundbank;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UsersDaoImplTest {
@Autowired
private UsersDao usersDao;
/**
* 单条件查询
*/
@Test
public void test1(){
Specification<Users> spec=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
/**
* @return Predicate:定义了查询条件
* @param Root<Users> root:封装查询条件的对象
* @param CriteriaQuery<?> query:定义了一个基本的查询.一般不使用
* @param CriteriaBuilder cb:创建一个查询条件
*/
Predicate predicate = criteriaBuilder.equal(root.get("username"), "金泰妍");
return predicate;
}
};
List<Users> list = this.usersDao.findAll(spec);
for (Users u:list) {
System.out.println(u);
}
}
/**
* 多条件查询 方式一
* 需求:使用用户姓名以及年龄查询数据
*/
@Test
public void test2(){
Specification<Users> spec=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> list=new ArrayList<>();
list.add(criteriaBuilder.equal(root.get("username"),"金泰妍"));
list.add(criteriaBuilder.equal(root.get("userage"),20));
Predicate[] arr=new Predicate[list.size()];
return criteriaBuilder.or(list.toArray(arr));
}
};
List<Users> list = this.usersDao.findAll(spec);
for (Users u:list) {
System.out.println(u);
}
}
/**
* 多条件查询 方式二
*/
@Test
public void test3(){
Specification<Users> spec=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.or(criteriaBuilder.equal(root.get("username"),"金泰妍"),criteriaBuilder.equal(root.get("userage"),20));
}
};
List<Users> list = this.usersDao.findAll(spec);
for (Users u:list) {
System.out.println(u);
}
}
/**
* 多条件查询 方式二加分页
*/
@Test
public void test4(){
Specification<Users> specification = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.like(root.get("username").as(String.class),"金%");
}
};
//分页
Pageable pageable=new PageRequest(0,2);
Page<Users> all = this.usersDao.findAll(specification, pageable);
List<Users> list = all.getContent();
System.out.println(all.getTotalElements());
System.out.println(all.getTotalPages());
for (Users u:list) {
System.out.println(u);
}
}
/**
* 多条件查询 方式二加排序
*/
@Test
public void test5(){
Specification<Users> specification = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.like(root.get("username").as(String.class),"金%");
}
};
//排序
Sort sort=new Sort(Sort.Direction.DESC,"userage");
List<Users> all = this.usersDao.findAll(specification, sort);
for (Users u:all) {
System.out.println(u);
}
}
/**
* 多条件查询 方式二 排序+分页
* 排序放入分页中
*/
@Test
public void test6(){
//排序
Sort sort=new Sort(Sort.Direction.ASC,"userage");
//分页
Pageable pageable=new PageRequest(0,2,sort);
//多条件查询
Specification<Users> specification=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.like(root.get("username").as(String.class),"金%");
}
};
Page<Users> all = this.usersDao.findAll(specification, pageable);
for (Users u:all) {
System.out.println(u);
}
}
}
上一篇: JAVA学习笔记_面向对象