Java框架_SpringBoot整合Spring Data JPA

一、Spring Data JPA介绍

        spring data:其实就是spring 提供的一个操作数据的框架。而spring data JPA 只是spring data 框架下的一个基于JPA标准操作数据的模块。

        spring data jpa :基于JPA的标准对数据进行操作。简化操作持久层的代码,只需要编写接口就可以。

二、spring boot 整合spring data jpa

1、搭建整合环境
Java框架_SpringBoot整合Spring Data JPA_第1张图片
2、修改pom.xml文件添加所需依赖

	4.0.0
	com.lxp
	framework
	0.0.1-SNAPSHOT
	
	
	
		org.springframework.boot
		spring-boot-starter-parent
		1.5.10.RELEASE
	
	
	
		1.7
	
	
	
	
	
		
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
        
            org.springframework.boot
            spring-boot-starter-test
        
	    
	    
		
			mysql
			mysql-connector-java
		
	    
	    
        
	        com.alibaba
            druid
            1.0.9
	    
    
    	
		
			org.springframework.boot
			spring-boot-starter-data-jpa
		
		
    
3、在项目中添加application.properties文件,添加数据库配置以及JPA配置
# 数据库配置
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/framework
spring.datasource.username = root
spring.datasource.password = root

# SpringData JPA 配置
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql = true
4、添加实体类
@Entity
@Table(name = "sys_users")
public class SysUsers {

	@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 = "addr")
	private String addr;

	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 getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}
5、添加接口
public interface SysUsersRepository extends JpaRepository {

	/**
	 * JpaRepository
	 * 
	 * T:当前需要映射的实体。 ID:当前映射实体中ID的类型
	 */
}
6、创建启动类
@SpringBootApplication
public class AppStart {

	public static void main(String[] args) {
		SpringApplication.run(AppStart.class, args);
	}
}
7、编写测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AppStart.class)
public class RepositoryTest {

	@Autowired
	private SysUsersRepository sysUsersRepository;

	@Test
	public void save() {
		SysUsers users = new SysUsers();
		users.setAddr("USA");
		users.setAge(12);
		users.setName("lucy");

		this.sysUsersRepository.save(users);
	}
}

启动测试方法,如果数据库有插入这个人,那么这个接口就是可行的。

三、Spring Data JPA提供的核心接口

  • Repository 接口
  • CrudRepository 接口
  • pagingAndSortingRepository 接口
  • JpaRepository 接口
  • JpaSpecificationExecutor 接口

四、Repository接口的使用

     该接口给我们提供了两种查询方法:方法名称命名查询方式,基于@Query注解的查询与更新。

1、方法名称命名查询方式
  • 编写接口
public interface SysUsersRepository extends Repository {

	/**
	 * 方法名称名称查询方式
	 * 
	 * 名称规则:方法的名称必须遵循驼峰式名称规则 : findBy(关键字) + 属性名称(首字母大写) + 查询条件(首字母大写)
	 */

	// 单条件
	List findByName(String name);

	// 多条件(and)
	List findByNameAndAge(String name, int age);

	// 多条件(or)
	List findByNameOrAge(String name, int age);

	// 单条件(like)
	List findByNameLike(String name);
}
  • 编写测试代码
package com.lxp.test.repository;

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.lxp.AppStart;
import com.lxp.dao.SysUsersRepository;
import com.lxp.pojo.SysUsers;

/**
 * @author lxp
 * @date 2018年7月12日 上午9:32:31
 * @parameter
 * @return
 */

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AppStart.class)
public class RepositoryTest {

	@Autowired
	private SysUsersRepository sysUsersRepository;

	/**
	 * 单条件查询测试
	 */
	@Test
	public void TestfindByName() {
		List ls = this.sysUsersRepository.findByName("Lucy");
		for (SysUsers sysUsers : ls) {
			System.out.println(sysUsers);
		}

		List ls2 = this.sysUsersRepository.findByNameLike("%Lucy%");
		for (SysUsers sysUsers : ls2) {
			System.out.println(sysUsers);
		}
	}

	/**
	 * 多条件查询测试
	 */
	@Test
	public void TestfindByNameAndAge() {
		List ls = this.sysUsersRepository.findByNameAndAge("Lucy", 12);
		for (SysUsers sysUsers : ls) {
			System.out.println(sysUsers);
		}

		List ls2 = this.sysUsersRepository.findByNameOrAge("Lucy", 12);
		for (SysUsers sysUsers : ls2) {
			System.out.println(sysUsers);
		}
	}
}
2、基于@Query注解的查询与更新

  • 编写接口
public interface SysUsersRepositoryQueryAnnotation extends Repository {

	// 注意点:这种写法语句中 SysUsers 必须是和实体类名称一样 不能是数据里的表名称(sys_users)
	// 底层会对HQL语句就行转换,这种方法nativeQuery默认为false
	@Query("from SysUsers where name = ?")
	List QueryByNameHQL(String name);

	// 注意点:nativeQuery= true 说明这的语句就是正常的SQL语句,底层不会对改语句进行转换
	@Query(value = "select * from sys_users where name = ?", nativeQuery = true)
	List QueryByNameSQL(String name);

	@Query("update SysUsers set name = ? where id =?")
	@Modifying // 需要加上@Modifying Annotation
	void UpdateSysUsersNameById(String name, Integer id);
}

  • 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AppStart.class)
public class RepositoryTest {

	@Autowired
	private SysUsersRepositoryQueryAnnotation sysUsersRepositoryQueryAnnotation;

	@Test
	public void TestQueryByNameHQL() {
		List ls = this.sysUsersRepositoryQueryAnnotation.QueryByNameHQL("Lucy");
		for (SysUsers sysUsers : ls) {
			System.out.println(sysUsers);
		}

		List ls2 = this.sysUsersRepositoryQueryAnnotation.QueryByNameSQL("Lucy");
		for (SysUsers sysUsers : ls2) {
			System.out.println(sysUsers);
		}
	}

	@Test
	@Transactional // 注意: @Transactional和@Test一起用的时候事务是自动回滚的
					// 所以需要加上@Rollback(false) 标识不回滚
	@Rollback(false)
	public void TestUpdateSysUsersNameById() {
		this.sysUsersRepositoryQueryAnnotation.UpdateSysUsersNameById("LucyLily", 2);
	}

}

五、CrudRepository接口的使用

        CrudRepository接口,主要是完成一些增删改查的操作。注意:CrudRepository接口集成了Repository接口。

        Java框架_SpringBoot整合Spring Data JPA_第2张图片

  • 编写接口
public interface SysUsersCrudRepository extends CrudRepository {
    /**
	 * 先不需要写接口
	 */
}
  • 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AppStart.class)
public class RepositoryTest {

	@Autowired
	private SysUsersCrudRepository sysUsersCrudRepository;

	@Test
	public void TestSysUsersCrudRepositorySave() {
		SysUsers users = new SysUsers();
		users.setAddr("北京");
		users.setAge(25);
		users.setName("李四");

		this.sysUsersCrudRepository.save(users);
	}

	@Test
	public void TestSysUsersCrudRepositoryUpdate() {
		SysUsers users = new SysUsers();
		users.setId(5);
		users.setAddr("北京海淀区");
		users.setAge(25);
		users.setName("李四");

		this.sysUsersCrudRepository.save(users);
	}

	@Test
	public void TestSysUsersCrudRepositoryFindOne() {

		SysUsers users = this.sysUsersCrudRepository.findOne(5);
		System.out.println(users);

		List ls = (List) this.sysUsersCrudRepository.findAll();
		for (SysUsers sysUsers : ls) {
			System.out.println(sysUsers);
		}
	}

	@Test
	public void TestSysUsersCrudRepositoryDel() {
		this.sysUsersCrudRepository.delete(4);
	}

}

注意:在试用CrudRepository接口的时候无需自己添加@Transactional回滚,因为CrudRepository为需要添加事务的方法已经添加了事务。

六、PagingAndSortRepository接口使用

        pagingAndSortRepository接口,提供了分页与排序的操作,注意:该接口集成了CrudRepository接口。

Java框架_SpringBoot整合Spring Data JPA_第3张图片

  • 编写接口
public interface SysUsersPagingAndSortRepository extends PagingAndSortingRepository {

}
  • 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AppStart.class)
public class RepositoryTest {

	@Autowired
	private SysUsersPagingAndSortRepository sysUsersPagingAndSortRepository;

	@Test
	public void TestSysUsersPagingAndSortRepositorySort() {

		Order order = new Order(Direction.DESC, "id"); // 定义排序规则
		Sort sort = new Sort(order); // 封装了排序的规则
		Iterable ls = this.sysUsersPagingAndSortRepository.findAll(sort);
		for (SysUsers sysUsers : ls) {
			System.out.println(sysUsers);
		}
	}

	@Test
	public void TestSysUsersPagingAndSortRepositoryPaging() {

		// Pageable:封装了分页的参数:当前页,每页显示的条数,注意:他的当前也开始数
		// Pageable pageable = new PageRequest(page, size, sort);
		// page:当前页 ,size :每页显示的条数,sort: 排序

		Order order = new Order(Direction.DESC, "id"); // 定义排序规则
		Sort sort = new Sort(order); // 封装了排序的规则

		Pageable pageable = new PageRequest(0, 2, sort);
		Page page = this.sysUsersPagingAndSortRepository.findAll(pageable);

		System.out.println("总条数:" + page.getTotalElements());
		System.out.println("总页数:" + page.getTotalPages());

		List ls = page.getContent();
		for (SysUsers sysUsers : ls) {
			System.out.println(sysUsers);
		}

	}

}

七、JpaRepository 接口使用

        JpaRepository接口特点:该接口集成PagingAndSortingRepository接口,该接口对继承的父接口中方法的返回值进行适配。

  •     编写接口
public interface SysUsersJpaRepository extends JpaRepository {

	/**
	 * Repository
	 * 
	 * T:当前需要映射的实体。 ID:当前映射实体中ID的类型
	 */

}

  • 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AppStart.class)
public class RepositoryTest {

	@Autowired
	private SysUsersJpaRepository sysUsersJpaRepository;

	@Test
	public void TestSysUsersJpaRepository() {

		Order order = new Order(Direction.DESC, "id");
		Sort sort = new Sort(order);
		List ls = this.sysUsersJpaRepository.findAll(sort);
		for (SysUsers sysUsers : ls) {
			System.out.println(sysUsers);
		}
	}

}

八、JPASpecificationExecutor接口的使用

        JPASpecificationExecutor接口:该接口主要是提供了多条件查询的支持,并且可以在查询中添加分页和排序。

        注意: JPASpecificationExecutor接口单独存在,完全独立。使用时需配合其他接口使用。
  • 编写接口
public interface SysUserJPASpecificationExecutor extends JpaSpecificationExecutor, JpaRepository {

}
  • 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AppStart.class)
public class RepositoryTest {

	@Autowired
	private SysUserJPASpecificationExecutor sysUserJPASpecificationExecutor;

	/**
	 * 单条件查询
	 */
	@Test
	public void TestSysUsersJpaRepository() {

		/**
		 * Specification:用户封装查询条件。
		 */
		Specification spec = new Specification() {
			@Override
			public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
				/**
				 * Predicate: 封装了单个查询条件; root: 查询对象属性的封装。
				 * query:封装了要查询中的各个部分的信息(eg:select from order by) cb:查询条件的构造器
				 */
				// where name = 'Lucy'
				Predicate pre = cb.equal(root.get("name"), "LucyLily");

				return pre;
			}
		};

		List ls = this.sysUserJPASpecificationExecutor.findAll(spec);
		for (SysUsers user : ls) {
			System.out.println(user);
		}
	}

	/**
	 * 多条件查询
	 */
	@Test
	public void TestSysUsersJpaRepository2() {
		Specification spec = new Specification() {
			@Override
			public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
				// where name = ? and age = ?

				List list = new ArrayList<>();
				list.add(cb.equal(root.get("name"), "LucyLily"));
				list.add(cb.equal(root.get("age"), 12));

				Predicate[] arr = new Predicate[list.size()];

				return cb.and(list.toArray(arr)); // cb.or(list.toArray(arr));
				/**
				 * 第二种多条件方式
				 */
				// return cb.and(cb.equal(root.get("name"), "LucyLily"),cb.equal(root.get("age"), 12));
			}
		};

		Sort sort = new Sort(new Order(Direction.DESC, "id"));
		List ls = this.sysUserJPASpecificationExecutor.findAll(spec, sort);
		for (SysUsers user : ls) {
			System.out.println(user);
		}
	}

}

九、关联映射操作

1、一对多的关联关系

      需求:角色与用户一对多的关联关系

      角色:一方

      用户:多方

  • 创建实体类 SysUsers.java与SysRoles.java
@Entity
@Table(name = "sys_users")
public class SysUsers {

	@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 = "addr")
	private String addr;

	@ManyToOne
	@JoinColumn(name = "rolesId")
	private SysRoles sysRoles;

	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 getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}

	public SysRoles getSysRoles() {
		return sysRoles;
	}

	public void setSysRoles(SysRoles sysRoles) {
		this.sysRoles = sysRoles;
	}

}
@Entity
@Table(name = "sys_roles")
public class SysRoles {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "rolesId")
	private Integer rolesId;

	@Column(name = "rolesName")
	private String rolesName;

	@OneToMany(mappedBy = "sysRoles")
	private Set sysUsers = new HashSet<>();

	public Integer getRolesId() {
		return rolesId;
	}

	public void setRolesId(Integer rolesId) {
		this.rolesId = rolesId;
	}

	public String getRolesName() {
		return rolesName;
	}

	public void setRolesName(String rolesName) {
		this.rolesName = rolesName;
	}

	public Set getSysUsers() {
		return sysUsers;
	}

	public void setSysUsers(Set sysUsers) {
		this.sysUsers = sysUsers;
	}

}
  • 测试一对多的关联关系(编写测试类)
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AppStart.class)
public class RepositoryTest {

	@Autowired
	private SysUsersJpaRepository sysUsersJpaRepository;

	@Test
	public void TestOneToManyAdd() {
		// 创建一个用户
		SysUsers user = new SysUsers();
		user.setAddr("AA....");
		user.setAge(30);
		user.setName("AAAAAA");

		// 创建一个角色
		SysRoles role = new SysRoles();
		role.setRolesName("超级管理员");
		// 用户角色关联
		role.getSysUsers().add(user);
		user.setSysRoles(role);

		// 保存
		sysUsersJpaRepository.save(user);
	}

	@Test
	public void TestOneToManyQuery() {

		SysUsers user = sysUsersJpaRepository.findOne(8);
		System.out.println(user);

		System.out.println(user.getSysRoles().getRolesName());
	}
}
2、多对多的关联关系

      需求:角色与菜单多对多的关联关系

  • 编写实体类SysRoles.java与Menus.java
@Entity
@Table(name = "sys_roles")
public class SysRoles {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "rolesId")
	private Integer rolesId;

	@Column(name = "rolesName")
	private String rolesName;

	@OneToMany(mappedBy = "sysRoles")
	private Set sysUsers = new HashSet<>();

	@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
	// @JoinTable映射中间表
	// JoinColumn 当前表的主键所关联中间表中的外键字段
	// inverseJoinColumns
	@JoinTable(name = "sys_roles_menus", joinColumns = @JoinColumn(name = "rolesId"), inverseJoinColumns = @JoinColumn(name = "menusId"))
	private Set roles = new HashSet();

	public Integer getRolesId() {
		return rolesId;
	}

	public void setRolesId(Integer rolesId) {
		this.rolesId = rolesId;
	}

	public String getRolesName() {
		return rolesName;
	}

	public void setRolesName(String rolesName) {
		this.rolesName = rolesName;
	}

	public Set getSysUsers() {
		return sysUsers;
	}

	public void setSysUsers(Set sysUsers) {
		this.sysUsers = sysUsers;
	}

	@Override
	public String toString() {
		return "SysRoles [rolesId=" + rolesId + ", rolesName=" + rolesName + "]";
	}

}
  • 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AppStart.class)
public class RepositoryTest {

	@Autowired
	private SysUsersJpaRepository sysUsersJpaRepository;

	@Test
	public void TestManyToManyAdd() {

		// 创建一个角色
		SysRoles sysRoles = new SysRoles();
		sysRoles.setRolesName("项目经理");

		// 创建菜单
		Menus menu = new Menus();
		menu.setMenusName("系统管理");
		menu.setPid(0);

		Menus menu2 = new Menus();
		menu2.setMenusName("基础管理");
		menu2.setPid(1);

		// 关联
		sysRoles.getMenus().add(menu);
		sysRoles.getMenus().add(menu2);

		menu.getRoles().add(sysRoles);
		menu2.getRoles().add(sysRoles);

		// 保存
		this.sysUsersJpaRepository.save(sysRoles);
	}

	@Test
	public void TestManyToManyQuery() {

		SysRoles roles = this.sysUsersJpaRepository.findOne(2);
		System.out.println(roles);

		Set set = roles.getMenus();
		for (Menus m : set) {
			System.out.println(m);
		}

	}
}

你可能感兴趣的:(后端开发)