本节由浅入深,再浅出学习Spring data JPA。我的学习路程是先通过spring整合Spring data JPA来具体学习,逐渐深入,学习完这些重要知识点后,再浅出到使用SpringBoot来整合Spring data JPA。
一.Spring整合Spring Data JPA
Spring Data JPA是Spring Data项目下的一个模块。提供了一套基于JPA标准操作数据库的简化方案,底层默认是依赖Hibernate JPA来实现的。
Spring Data JPA的技术特点:我们只需要定义接口并继承Spring Data JPA中所提供的接口就可以了。不需要编写接口实现类。
1.创建Spring Data JPA的项目,导入依赖,编写配置文件
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8.RC2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.1_spec</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.hibernate.common</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>5.1.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.5.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jandex</artifactId>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.28.0-GA</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.4.1.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.6.7.Final</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>mchange-commons-java</artifactId>
<version>0.2.19</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.6.7.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.28</version>
</dependency>
</dependencies>
applicationContext.xml相比之前spring整合Hibernate JPA时多了一个jpa的命名空间,其他也不用删除先,然后添加一个jpa的dao扫描,具体配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
https://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="driverClass" value="${jdbc.driver.class}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL"/>
<property name="generateDdl" value="true"/>
<property name="showSql" value="true"/>
</bean>
</property>
<property name="packagesToScan">
<list>
<value>com.haiexijun.pojo</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:component-scan base-package="com.haiexijun"/>
<jpa:repositories base-package="com.haiexijun.dao" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"/>
</beans>
jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/hibernate02
jdbc.driver.class=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=zc20020106
2.创建dao继承JpaRepository就好了,不用去写任何CRUD的接口的实现。
package com.haiexijun.dao;
import com.haiexijun.pojo.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface usersDao extends JpaRepository<Users,Integer> {
}
下面是一些测试代码:
import com.haiexijun.dao.usersDao;
import com.haiexijun.pojo.Users;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
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 javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class testDao {
@Autowired
private usersDao usersDao;
@PersistenceContext(name = "entityManagerFactory")
private EntityManager entityManager;
@Test
@Transactional
@Rollback(value = false)
public void testInsertUser(){
Users users=new Users();
users.setUserName("李四");
users.setUserAge(23);
usersDao.save(users);
}
@Test
public void test01(){
System.out.println(usersDao);
System.out.println(usersDao.getClass());
System.out.println("======");
JpaRepositoryFactory factory=new JpaRepositoryFactory(entityManager);
usersDao ud = factory.getRepository(com.haiexijun.dao.usersDao.class);
System.out.println(ud);
System.out.println(ud.getClass());
}
}
3.Repository接口详解
Repository接口是Spring Data JPA中为我们提供的所有接口中的顶层接口
repository提供了两种查询方式的支持:
(1)基于方法名称的命名规则查询
规则是什么? findBy+属性名称(属性名称的首写字母要大写)+查询条件(首字母要大写) 具体更多的规则查看Spring官网即可。
userDao02:
package com.haiexijun.dao;
import com.haiexijun.pojo.Users;
import org.springframework.data.repository.Repository;
import java.util.List;
@org.springframework.stereotype.Repository
public interface userDao02 extends Repository<Users,Integer> {
List<Users> findByUserNameIs(String name);
List<Users> findByUserNameLike(String name);
List<Users> findByUserNameAndUserAgeGreaterThanEqual(String name, Integer age);
}
测试用例:
@Test
@Transactional
@Rollback(value = false)
public void test02(){
List<Users> list= userDao02.findByUserNameIs("张三");
System.out.println(list);
}
@Test
@Transactional
@Rollback(value = false)
public void test03(){
List<Users> list= this.userDao02.findByUserNameLike("张%");
System.out.println(list);
}
@Test
@Transactional
@Rollback(value = false)
public void test04(){
List<Users> list=userDao02.findByUserNameAndUserAgeGreaterThanEqual("李四",20);
System.out.println(list);
}
(2)基于@Query注解查询
也有如下两种方式:
通过JPQL语句查询:
JPQL是通过Hibernate的HQL演变过来的。他和HQL语法极其相似。
@Query(value = "from Users where userName=:name")
List<Users> queryUsersByUserNameUseJPQL(@Param("name") String name);
@Query(value = "from Users where userName like :name")
List<Users> queryUsersByNameLikeUseJPQL(@Param("name") String name);
@Query("from Users where userName=?1 and userAge>?2")
List<Users> queryByUserNameAndUserAgeGreaterThanEqualUseJPQL(String name, int age);
@Query注解还可以通过sql语句来查询:
@Query(value = "select * from t_users where username=? ",nativeQuery = true)
List<Users> queryUsersByNameUseSQL(String name);
@Query(value = "select * from t_users where username like ?",nativeQuery = true)
List<Users> queryUsersByNameLikeUseSQL(String name);
@Query(nativeQuery = true,value = "select * from t_users where username=? and userage>?")
List<Users> queryByUserNameAndUserAgeGreaterThanEqualUseSQL(String name, int age);
(3)下面演示@Query注解的更新操作: jpql编写 DAO接口update语句 还要添加@Modifying注解:
@Query("update Users set userAge =?2 where userId =?1 ")
@Modifying
void updateUserAgeById(Integer id,Integer age);
4.PagingAndSortingRepository接口
这个接口主要是帮助我们完成分页和排序处理。
(1)分页处理
我们创建一个新的Dao接口,继承至PagingAndSortingRepository接口。
我们点开这个接口的源代码查看后发现,这两个接口有2个重载的方法。这两个方法需要传入不同的参数,一个需要Sort类型的参数(用于排序),一个需要Pageable类型的参数(用于分页)。并且我们也会发现这两个方法的名称都叫做findAll(),也就是说,是对数据库表当中的所有的数据进行查询的。
package com.haiexijun.dao;
import com.haiexijun.pojo.Users;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface UserDao01 extends PagingAndSortingRepository<Users,Integer> {
}
如果你比较懒,不想再创建一个人接口,也没有关系,因为我们之前用的UsersDao就是就继承自JPArepository接口,而JPArepository接口又继承了PagingAndSortingRepository这个接口,也就是说你可以用之前得Dao就可以了。
然后回到我们的测试代码当中。编写如下的测试方法来学习这个接口的相关操作。
比如说我要对数据表中所有的数据做分页处理:
@Test
@Transactional
@Rollback(value = false)
public void test12(){
Integer page=0;
Integer size=3;
Pageable pageable =PageRequest.of(page,size);
Page<Users> p= usersDao.findAll(pageable);
System.out.println("数据得总条数:"+p.getTotalElements());
System.out.println("数据的总页数:"+p.getTotalPages());
List<Users> list=p.getContent();
System.out.println("分页得结果:"+list);
}
(2)排序处理
@Test
@Transactional
@Rollback(value = false)
public void test13(){
Sort sort=Sort.by(Sort.Direction.DESC,"userId");
List<Users> list=usersDao.findAll(sort);
System.out.println(list);
}
@Test
@Transactional
@Rollback(value = false)
public void test14(){
Sort.Order order1=new Sort.Order(Sort.Direction.DESC,"userAge");
Sort.Order order2=new Sort.Order(Sort.Direction.ASC,"userId");
Sort sort=Sort.by(order1,order2);
List<Users> list=usersDao.findAll(sort);
System.out.println(list);
}
5.JpaSpecificationExecutor接口
这个接口支持多条件查询,同时支持分页与排序。
看下图,会发现JpaSpecificationExecutor接口并没有继承自任何的接口。
我们要新新建一个dao:
package com.haiexijun.dao;
import com.haiexijun.pojo.Users;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface UserDao01 extends JpaSpecificationExecutor<Users>, JpaRepository<Users,Integer> {
}
(1)单条件查询:
@Test
@Transactional
@Rollback(value = false)
public void test15(){
Specification<Users> spec=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Predicate pre= criteriaBuilder.equal(root.get("userName"),"张三");
return pre;
}
};
List<Users> list= userDao01.findAll(spec);
System.out.println(list);
}
(2)多条件查询
方式一:
@Test
@Transactional
@Rollback(value = false)
public void test16(){
Specification<Users> spec=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
List<Predicate> list=new ArrayList<Predicate>();
list.add(criteriaBuilder.equal(root.get("userName"),"张三"));
list.add(criteriaBuilder.equal(root.get("userAge"),26));
Predicate[] arr=new Predicate[list.size()];
return criteriaBuilder.and(list.toArray(arr));
}
};
List<Users> list = userDao01.findAll(spec);
System.out.println(list);
}
方式二:
@Test
@Transactional
@Rollback(value = false)
public void test17(){
Specification<Users> spec=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.or(criteriaBuilder.equal(root.get("userName"),"张三"),criteriaBuilder.equal(root.get("userAge"),27));
}
};
List<Users> list = userDao01.findAll(spec);
System.out.println(list);
}
多条件查询的分页查询:
@Test
@Transactional
@Rollback(value = false)
public void test18(){
Specification<Users> spec=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.like(root.get("userName").as(String.class),"张%");
}
};
Pageable pageable=PageRequest.of(0,2);
Page<Users> page= userDao01.findAll(spec,pageable);
System.out.println("总条数:"+page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
System.out.println(page.getContent());
}
多条件查询的排序操作:
/**
* 需求:查询姓张的用户,并按用户年龄降序排序
*/
@Test
@Transactional
@Rollback(value = false)
public void test19(){
//条件
Specification<Users> spec=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.like(root.get("userName").as(String.class),"张%");
}
};
//排序
Sort sort=Sort.by(Sort.Direction.DESC,"userAge");
List<Users> list=userDao01.findAll(spec,sort);
System.out.println(list);
}
多条件查询的分页加排序操作:
@Test
@Transactional
@Rollback(value = false)
public void test20(){
Sort sort=Sort.by(Sort.Direction.DESC,"userAge");
Pageable pageable=PageRequest.of(0,2,sort);
Specification<Users> spec=new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.like(root.get("userName").as(String.class),"张%");
}
};
Page<Users> page=userDao01.findAll(spec,pageable);
System.out.println("总条数:"+page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
System.out.println(page.getContent());
}
6.用户自定义Repository接口
我们在开发的时候,如果觉得他给的接口不足以满足需求的话,我们也可以自己去定义自己的Repository接口。
具体可以如下:
在repositoey包下面创建我们自己定义的Reposity接口,里面定义方法:
package com.haiexijun.repository;
import com.haiexijun.pojo.Users;
public interface UsersRepository {
public Users findUserById(Integer userId);
}
然后我们定义自己的Dao类实现这个接口:
package com.haiexijun.dao;
import com.haiexijun.pojo.Users;
import com.haiexijun.repository.UsersRepository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Repository
public class UserDaoImpl implements UsersRepository {
@PersistenceContext(name = "entityManagerFactory")
private EntityManager em;
@Override
public Users findUserById(Integer userId) {
return this.em.find(Users.class,userId);
}
}
我们也可以定义测试方法来调用一下这个dao:
/**
* 测试自定义Repository
*/
@Test
@Transactional
@Rollback(value = false)
public void test21(){
Users user= userDao.findUserById(5);
System.out.println(user);
}
7.关联映射的操作
(1) 一对一的关联关系
案例需求:用户与角色的一对一的联级关系
用户一方,角色一方。
案例具体的步骤如下:
分别创建两个实体类Users实体类和Roles实体类:
Users
package com.haiexijun.pojo;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "t_users")
public class Users implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "userid")
private Integer userId;
@Column(name = "username")
private String userName;
@Column(name = "userage")
private Integer userAge;
@OneToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "roleid")
private Roles roles;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getUserAge() {
return userAge;
}
public void setUserAge(Integer userAge) {
this.userAge = userAge;
}
public Roles getRoles() {
return roles;
}
public void setRoles(Roles roles) {
this.roles = roles;
}
@Override
public String toString() {
return "Users{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userAge=" + userAge +
", roles=" + roles +
'}';
}
}
Roles
package com.haiexijun.pojo;
import javax.persistence.*;
@Entity
@Table(name = "t_roles")
public class Roles {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "roleid")
private Integer roleId;
@Column(name = "rolename")
private String roleName;
@OneToOne(mappedBy = "roles")
private Users users;
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public Users getUsers() {
return users;
}
public void setUsers(Users users) {
this.users = users;
}
@Override
public String toString() {
return "Roles{" +
"roleId=" + roleId +
", roleName='" + roleName + '\'' +
'}';
}
}
之后会分别在两个实体类里面添加@OneToOne注解。在通过@JoinColumn(name = “roleid”)注解在任一个实体中定义好外键。
下面编写一个测试方法来具体演示如何操作:
@Test
@Transactional
@Rollback(value = false)
public void test22(){
Roles roles=new Roles();
roles.setRoleName("管理员");
Users users=new Users();
users.setUserAge(30);
users.setUserName("毛不易");
users.setRoles(roles);
roles.setUsers(users);
usersDao.save(users);
}
这样,我们就完成了根据一对一关联关系来操作了数据。
下面我们在来写一个方法来测试一下通过一对一关联关系的查询操作:
@Test
@Transactional
@Rollback(value = false)
public void test23(){
Users users=usersDao.findByUserId(7);
System.out.println("用户信息"+users);
Roles roles=users.getRoles();
System.out.println(roles);
}
(2)一对多的关联关系
上一节,通过用户和角色来学习了一对一的关联关系。这一节我们还是通过用户与角色来学习一对多的关联关系。
需求:一个用户可以对应多个角色,但是一个角色可以对应多个用户。
这是从角色到用户的一对多的关系,或者说是从用户到角色的多对一的关联关系。
角色是一方,用户是多方。
先把之前学习一对一关联关系的Roles和Users实体拿来,然后把里面的@OneToOne等一对一的相关的注解给删掉。然后重新编写一对一的关联关系的相关的注解和配置。
Roles
package com.haiexijun.pojo;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "t_roles")
public class Roles {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "roleid")
private Integer roleId;
@Column(name = "rolename")
private String roleName;
@OneToMany(mappedBy = "roles")
private Set<Users> users=new HashSet<>();
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public Set<Users> getUsers() {
return users;
}
public void setUsers(Set<Users> users) {
this.users = users;
}
}
Users
package com.haiexijun.pojo;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "t_users")
public class Users implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "userid")
private Integer userId;
@Column(name = "username")
private String userName;
@Column(name = "userage")
private Integer userAge;
@ManyToOne(cascade =CascadeType.PERSIST)
@JoinColumn(name = "roleid")
private Roles roles;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getUserAge() {
return userAge;
}
public void setUserAge(Integer userAge) {
this.userAge = userAge;
}
public Roles getRoles() {
return roles;
}
public void setRoles(Roles roles) {
this.roles = roles;
}
@Override
public String toString() {
return "Users{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userAge=" + userAge +
", roles=" + roles +
'}';
}
}
上面注意了,要把一的一方的toString()方法给去掉,负责一对多的查询操作会报错。
下面编写测试方式来学习:
@Test
@Transactional
@Rollback(value = false)
public void test24(){
Roles roles=new Roles();
roles.setRoleName("普通用户");
Users users=new Users();
users.setUserAge(50);
users.setUserName("黄晓明");
roles.getUsers().add(users);
users.setRoles(roles);
usersDao.save(users);
}
}
下面再来编写代码学习一下一对多的关联查询:
@Test
@Transactional
@Rollback(value = false)
public void test25(){
Users users= usersDao.findByUserName("黄晓明");
System.out.println(users);
Roles roles=users.getRoles();
System.out.println(roles);
}
(3)多对多的关联操作
需求:一个角色可以拥有多个菜单,一个菜单可以分配给多个角色。
角色是多方,菜也是多方。
我们需要用到之前的Roles的实体以及新创建一个Menus实体
Roles
package com.haiexijun.pojo;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "t_roles")
public class Roles {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "roleid")
private Integer roleId;
@Column(name = "rolename")
private String roleName;
@ManyToMany
@JoinTable(name = "t_roles_menus",joinColumns = @JoinColumn(name = "role_id"),inverseJoinColumns = @JoinColumn(name ="menu_id"))
private Set<Menus> menus=new HashSet<>();
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public Set<Menus> getMenus() {
return menus;
}
public void setMenus(Set<Menus> menus) {
this.menus = menus;
}
}
Menus
package com.haiexijun.pojo;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "t_nemus")
public class Menus {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "menuid")
private Integer menuId;
@Column(name = "menuname")
private String menuName;
@Column(name = "namuurl")
private String menuUrl;
@Column(name = "menuid")
private Integer fatherId;
@ManyToMany(mappedBy ="menus" )
private Set<Roles> roles=new HashSet<>();
public Integer getMenuId() {
return menuId;
}
public void setMenuId(Integer menuId) {
this.menuId = menuId;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMenuUrl() {
return menuUrl;
}
public void setMenuUrl(String menuUrl) {
this.menuUrl = menuUrl;
}
public Integer getFatherId() {
return fatherId;
}
public void setFatherId(Integer fatherId) {
this.fatherId = fatherId;
}
public Set<Roles> getRoles() {
return roles;
}
public void setRoles(Set<Roles> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "Menus{" +
"menuId=" + menuId +
", menuName='" + menuName + '\'' +
", menuUrl='" + menuUrl + '\'' +
", fatherId=" + fatherId +
", roles=" + roles +
'}';
}
}
下面编写测试代码来演示相关的操作:
@Test
@Transactional
@Rollback(value = false)
public void test26(){
Roles roles=new Roles();
roles.setRoleName("超级管理员");
Menus menus1=new Menus();
menus1.setMenuName("xxx管理平台");
menus1.setFatherId(-1);
menus1.setMenuUrl(null);
Menus menus2=new Menus();
menus2.setMenuName("用户管理");
menus2.setFatherId(1);
menus2.setMenuUrl(null);
roles.getMenus().add(menus1);
roles.getMenus().add(menus2);
menus1.getRoles().add(roles);
menus2.getRoles().add(roles);
usersDao.save(roles);
}
二.SpringBoot整合使用Spring Data Jpa
1.创建springboot的项目:
2.然后对项目的配置文件进行配置:
#数据库的配置
##指定为update,每次启动项目检测表结构有变化的时候会新增字段,表不存在时会新建,如果指定create,则每次启动项目都会清空数据并删除表,再新建
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database=mysql
#指定jpa的自动表生成策略,驼峰自动映射为下划线格式
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.datasource.url=jdbc:mysql://localhost:3306/jpa?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=zc20020106
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#是否显示sql在控制台
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto
create: 每次应用启动的时候会重新根据实体建立表,之前的表和数据都会被删除。 create-drop: 和上面的功能一样,但是多了一样,就是在应用关闭的时候,也就是sessionFactory一关闭,会把表删除。 update: 最常用的,第一次启动根据实体建立表结构,之后启动会根据实体的改变更新表结构,之前的数据都在。 validate: 会验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值,运行程序会校验实体字段与数据库已有的表的字段类型是否相同,不同会报错
然后创建一个pojo包,里面创建一个实体类,具体代码如下:
package com.example.springbootjpa.pojo;
import javax.persistence.*;
@Entity
@Table(name="student",indexes = {@Index(name="id",columnList = "id",unique = true),@Index(name = "name",columnList = "name",unique = true)})
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "password")
private String password;
@Column(name = "email")
private String email;
@Column(name = "age")
private Integer age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
3 然后编写一个StudentDao并继承自JpaRepository,由此我们已经继承了大部分可用的CRUD操作,针对基础操作,DAO完全不用写任何方法。
package com.example.springbootjpa.dao;
import com.example.springbootjpa.pojo.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentDao extends JpaRepository<Student,Long> {
}
4.接着编写一个服务接口,添加学生的保存、删除、查询全部和分页查询等的方法。
package com.example.springbootjpa.service;
import com.example.springbootjpa.pojo.Student;
import org.springframework.data.domain.Pageable;
public interface StudentService {
public void save(Student student);
public void delete(Student student);
public Object findPage(Pageable pageable);
}
5.继续编写服务实现类并调用DAO实现相应功能
package com.example.springbootjpa.service.impl;
import com.example.springbootjpa.dao.StudentDao;
import com.example.springbootjpa.pojo.Student;
import com.example.springbootjpa.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao studentDao;
@Override
public void save(Student student) {
studentDao.save(student);
}
@Override
public void delete(Student student) {
studentDao.delete(student);
}
@Override
public Object findPage(Integer PageNum,Integer pageSize) {
Pageable pageable= PageRequest.of(PageNum,pageSize);
return studentDao.findAll(pageable);
}
}
6.接着编写一个学生控制器,调用服务接口实现对应功能。
package com.example.springbootjpa.controller;
import com.example.springbootjpa.pojo.Student;
import com.example.springbootjpa.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
@PostMapping("/save")
public void save(@RequestBody Student student){
studentService.save(student);
}
@PostMapping("/delete")
public void delete(@RequestBody Student student){
studentService.delete(student);
}
@GetMapping("/findAll")
public Object findAll(){
return studentService.findAll();
}
@GetMapping("/findPage")
public Object findPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize){
return studentService.findPage(pageNum,pageSize);
}
}
到这里基本的整合与使用都介绍完了。如果以后我遇到其他的用法和知识点我再回来添加。
|