SpringBoot整合Spring Data JPA
一、Spring Data JPA介绍
Spring Data 就是提供了一个操作数据的框架。而Spring Data JPA就是Spring Data 框架下的一个基于JPA标准操作数据的模块。
简化操作持久层代码,只要编写接口即可。
二、整合Spring Data JPA
pom.xml
<dependencies>
<!-- web启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- thymeleaf启动器的坐标 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- jpa启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 测试启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- mysql数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.5</version>
</dependency>
</dependencies>
添加application.properties
spring.datasource.dirverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
实体类
/**
* 实体类
* @author 24957
*
*/
@Entity//标记实体类
@Table(name="t_users")//数据库中表名
public class Users {
@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;
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层接口
/**
*
* 第一个参数 T:指的是实体类的类型
* 第二个参数:ID:指的是实体类主键的数据类型
* @author 24957
*
*/
public interface UsersDao extends JpaRepository<Users, Integer> {
}
启动类
/**
* 启动类
* @author 24957
*
*/
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
测试类
/**
* 测试类
* @author 24957
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=App.class)
public class TestUsers {
@Autowired
private UsersDao usersDao;
@Test
public void testSave() {
Users users = new Users();
users.setName("庞杰");
users.setAge(22);
users.setAddress("天津武清");
usersDao.save(users);//save()方法来自于继承的接口中
}
}
save()方法
/**
* 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);
运行测试类:成功后会在数据库中创建好“t_users”表,并且将Users数据添加到表中。
控制台输出:
Hibernate: insert into t_users (address, age, name) values (?, ?, ?)
三、Spring Data JPA提供核心接口
Repository接口
CrudRepository接口
PagingAndSortingRepository接口
JpaRepository接口
JPASpecificationExecutor接口
1、Repository接口
提供了方法名称命名查询方式
接口
/**
*
* 方法名称命名查询方式
* @author pangjie
*
*/
public interface UsersRepository extends Repository<Users,Integer> {
/*
* 方法命名:驼峰式,find+By+查询条件
*/
List<Users> findByName(String name);
}
测试类
@Test
public void testFindByName() {
List<Users> findByName = usersRepository.findByName("庞杰");
System.out.println(findByName.toString());
}
提供了基于@Query注解查询与更新
接口
/**
*
* @Query
* @author pangjie
*
*/
public interface UsersQuery extends Repository<Users, Integer> {
@Query(value="select * from t_users where name=?",nativeQuery = true)
List<Users> queryByNameUseHQL(String name);
@Query(value="update t_users set name=? where id=?",nativeQuery = true)
@Modifying//进行更新操作
int updateUsers(String name,Integer id);
}
测试类
@Test
public void testQueryByName() {
List<Users> list = usersQuery.queryByNameUseHQL("谢知松");
for (Users users : list) {
System.out.println(users);
}
}
@Test
@Transactional
@Rollback(false)//取消自动回滚
public void testUpdateUsers() {
int updateUsers = usersQuery.updateUsers("谢天龙", 2);
if(updateUsers>0) {
System.out.println("success");
}else {
System.out.println("失败");
}
}
2、CrudRepository接口
主要完成增删改查操作
CrudRepository接口继承了Repository接口
接口
/**
* CrudRepository接口
* @author pangjie
*
*/
public interface UsersCrudRepository extends CrudRepository<Users, Integer> {
}
测试
/**
* 添加、修改方法都是save(对象)
* 如果是新对象则进行添加操作
* 如果是数据库中存在的对象则进行修改操作。
*/
@Test
public void testCrudSave() {
Users users = new Users();
users.setId(8);
users.setAddress("武当山");
users.setAge(102);
users.setName("张翠山");
Users users2 = usersCrudRepository.save(users);
}
/**
* 查询操作
* findAll--查询全部
* findById--查询一条数据
*/
@Test
public void testFindOne() {
Iterable<Users> findAll = usersCrudRepository.findAll();
for (Users users : findAll) {
System.out.println(users);
}
}
/**
* 删除操作
*/
@Test
public void testDelete() {
usersCrudRepository.deleteById(8);
}
3、PagingAndSortingRepository接口
特点:提供了分页与排序的操作。
继承了CrudRepository接口
分页加排序
接口
/**
* PagingAndSortingRepository 分页,排序
* @author pangjie
*
*/
public interface UsersSortAndPaging extends PagingAndSortingRepository<Users, Integer> {
}
测试类
/**
* 分页+排序
*/
@Test
public void testPaging() {
//Order对象,定义排序规则
Order order = new Order(Direction.DESC, "id");
//Sort对象封装了排序规则
Sort sort = new Sort(order);
Pageable pagable = new PageRequest(0, 2, sort);
Page<Users> page = this.usersSortAndPaging.findAll(pagable);
List<Users> list = page.getContent();
for (Users users : list) {
System.out.println(users);
}
}
4、JpaRepository接口(用的比较多)
JpaRepository接口继承了PagingAndSortingRepository接口
对继承的父接口中的返回值进行适配。(无需进行强制类型装换)
5、JPASpecificationExecutor接口
提供了多条件查询,并且可以在查询中添加排序与分页。
此接口完全独立存在,通常与JpaRepository配合使用
/**
* JpaSpecificationExecutor 接口
* @author pangjie
*
*/
public interface UserJPASpecificationExecutor extends JpaRepository<Users, Integer>,JpaSpecificationExecutor<Users> {
}
/**
* 单条件查询
*/
@Test
public void testSpecifiation() {
/**
* Specification<Users>() 用于封装查询条件
*/
Specification<Users> spec = new Specification<Users>() {
/**
* Predicate:封装了单个的查询条件
* Root<Users> root 查询对象属性的封装
* CriteriaQuery<?> query 封装了查询中的各个部分的信息
* CriteriaBuilder criteriaBuilder 定义不同的查询条件。
*/
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
/**
* equal(root,query)
* 第一个参数:查询条件的属性、
* 第二个参数:条件的值
*/
Predicate predicate = criteriaBuilder.equal(root.get("name"),"庞杰");
return predicate;
}
};
List<Users> list = userSpecification.findAll(spec);
for (Users users : list) {
System.out.println(users);
}
}
/**
* 多条件查询
*/
@Test
public void testSpecifiation2() {
/**
* Specification<Users>() 用于封装查询条件
*/
Specification<Users> spec = new Specification<Users>() {
/**
* Predicate:封装了单个的查询条件
* Root<Users> root 查询对象属性的封装
* CriteriaQuery<?> query 封装了查询中的各个部分的信息
* CriteriaBuilder criteriaBuilder 定义不同的查询条件。
*/
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<>();
list.add(criteriaBuilder.equal(root.get("name"), "庞杰"));
list.add(criteriaBuilder.equal(root.get("age"), 22));
Predicate[] predicate = new Predicate[list.size()];
Predicate and = criteriaBuilder.and(list.toArray(predicate));
return and;
}
};
List<Users> list = userSpecification.findAll(spec);
for (Users users : list) {
System.out.println(users);
}
}
/**
* 多条件查询方法二
*/
@Test
public void testSpecifiation3() {
/**
* Specification<Users>() 用于封装查询条件
*/
Specification<Users> spec = new Specification<Users>() {
/**
* Predicate:封装了单个的查询条件
* Root<Users> root 查询对象属性的封装
* CriteriaQuery<?> query 封装了查询中的各个部分的信息
* CriteriaBuilder criteriaBuilder 定义不同的查询条件。
*/
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
/*
* List<Predicate> list = new ArrayList<>();
* list.add(criteriaBuilder.equal(root.get("name"), "庞杰"));
* list.add(criteriaBuilder.equal(root.get("age"), 22));
*
* Predicate[] predicate = new Predicate[list.size()];
*/
Predicate and = criteriaBuilder.or(criteriaBuilder.and(criteriaBuilder.equal(root.get("name"), "庞杰"),criteriaBuilder.equal(root.get("age"), 22)),criteriaBuilder.equal(root.get("id"), 2));
return and;
}
};
//Sort sort = new Sort(new Order(Direction.DESC,"id"));
List<Users> list = userSpecification.findAll(spec);
for (Users users : list) {
System.out.println(users);
}
}
6、关联映射操作
一对多:
角色与用户:一对多
角色:一
用户:多
修改Users,添加以下内容
@ManyToOne
@JoinColumn(name="roles_id") //维护外键
private Roles roles;
添加Roles类
/**
* 实体类
* @author pangjie
*
*/
@Entity//标记实体类
@Table(name="t_roles")//数据库中表名
public class Roles {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="rolesid")
private Integer rolesid;
@Column(name="rolesname")
private String rolesname;
@OneToMany(mappedBy = "roles")//与Users对象对应。
private Set<Users> users = 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<Users> getUsers() {
return users;
}
public void setUsers(Set<Users> users) {
this.users = users;
}
}
测试一对多的关联关系
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=App.class)
public class OneToMoney {
@Autowired
private UsersDao usersDao;
@Test
public void testSave() {
//创建用户
Users users = new Users();
users.setAddress("青岛");
users.setAge(40);
users.setName("黄渤");
//创建角色
Roles roles = new Roles();
roles.setRolesname("管理员");
//关联
roles.getUsers().add(users);//将用户放到角色的集合中
users.setRoles(roles);
//保存
usersDao.save(users);
}
}
修改Users实体类
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="roles_id") //维护外键
private Roles roles;
多对多关联
角色与菜单的多对多关系
角色:多方
菜单:多方
Roles(角色)实体添加
@ManyToMany
/*@JoinTable映射中间表
* joinColumns 当前表的主键所关联的中间表的外键
*/
@JoinTable(name = "t_roles_menus",joinColumns = @JoinColumn(name="role_id"),inverseJoinColumns = @JoinColumn(name="menus_id"))
private Set<Menus> menus = new HashSet<Menus>();
添加Menus实体
@Entity//标记实体类
@Table(name="t_menus")//数据库中表名
public class Menus {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "menusid")
private Integer menusid;
@Column(name = "menusname")
private String menusname;
@Column(name = "menusurl")
private String menusurl;
@Column(name = "fatherid")
private Integer fatherid;
@ManyToMany(mappedBy = "menus")
private Set<Roles> roles = new HashSet<>();
public Integer getMenusid() {
return menusid;
}
public void setMenusid(Integer menusid) {
this.menusid = menusid;
}
public String getMenusname() {
return menusname;
}
public void setMenusname(String menusname) {
this.menusname = menusname;
}
public String getMenusurl() {
return menusurl;
}
public void setMenusurl(String menusurl) {
this.menusurl = menusurl;
}
public Integer getFatherid() {
return fatherid;
}
public void setFatherid(Integer fatherid) {
this.fatherid = fatherid;
}
}
测试多对多关联关系
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=App.class)
public class ManyToMany {
@Autowired
private RolesRepository rolesRepository;
@Test
public void testSave() {
//创建角色
Roles roles = new Roles();
roles.setRolesname("项目经理");
//创建菜单
Menus menus = new Menus();
menus.setMenusname("项目系统");
menus.setFatherid(0);
Menus menus2 = new Menus();
menus2.setMenusname("项目菜单");
menus2.setFatherid(1);
//关联
roles.getMenus().add(menus);
roles.getMenus().add(menus2);
menus.getRoles().add(roles);
menus2.getRoles().add(roles);
//保存
rolesRepository.save(roles);
}
}