- 一.Spring整合Spring Data JPA
- 1.创建Spring Data JPA的项目,导入依赖,编写配置文件
- 2.创建dao继承JpaRepository就好了,不用去写任何CRUD的接口的实现。
- 3.Repository接口详解
- 4.PagingAndSortingRepository接口
- 5.JpaSpecificationExecutor接口
- 6.用户自定义Repository接口
- 7.关联映射的 *** 作
- 二.SpringBoot整合使用Spring Data Jpa
- 1.创建springboot的项目:
- 2.然后对项目的配置文件进行配置:
- 3 然后编写一个StudentDao并继承自JpaRepository,由此我们已经继承了大部分可用的CRUD *** 作,针对基础 *** 作,DAO完全不用写任何方法。
- 4.接着编写一个服务接口,添加学生的保存、删除、查询全部和分页查询等的方法。
- 5.继续编写服务实现类并调用DAO实现相应功能
- 6.接着编写一个学生控制器,调用服务接口实现对应功能。
一.Spring整合Spring Data JPA本节由浅入深,再浅出学习Spring data JPA。我的学习路程是先通过spring整合Spring data JPA来具体学习,逐渐深入,学习完这些重要知识点后,再浅出到使用SpringBoot来整合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.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-expressionartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.8.RC2version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>antlrgroupId>
<artifactId>antlrartifactId>
<version>2.7.7version>
dependency>
<dependency>
<groupId>org.dom4jgroupId>
<artifactId>dom4jartifactId>
<version>2.1.3version>
dependency>
<dependency>
<groupId>org.apache.geronimo.specsgroupId>
<artifactId>geronimo-jta_1.1_specartifactId>
<version>1.1.1version>
dependency>
<dependency>
<groupId>org.hibernate.commongroupId>
<artifactId>hibernate-commons-annotationsartifactId>
<version>5.1.2.Finalversion>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-coreartifactId>
<version>5.6.5.Finalversion>
dependency>
<dependency>
<groupId>org.hibernate.javax.persistencegroupId>
<artifactId>hibernate-jpa-2.1-apiartifactId>
<version>1.0.0.Finalversion>
dependency>
<dependency>
<groupId>org.jbossgroupId>
<artifactId>jandexartifactId>
<version>2.0.0.Finalversion>
dependency>
<dependency>
<groupId>org.javassistgroupId>
<artifactId>javassistartifactId>
<version>3.28.0-GAversion>
dependency>
<dependency>
<groupId>org.jboss.logginggroupId>
<artifactId>jboss-loggingartifactId>
<version>3.4.1.Finalversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.25version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.5version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-c3p0artifactId>
<version>5.6.7.Finalversion>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>mchange-commons-javaartifactId>
<version>0.2.19version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>5.6.7.Finalversion>
dependency>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-commonsartifactId>
<version>2.6.3version>
dependency>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-jpaartifactId>
<version>2.6.3version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.36version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.28version>
dependency>
dependencies>
applicationContext.xml相比之前spring整合Hibernate JPA时多了一个jpa的命名空间,其他也不用删除先,然后添加一个jpa的dao扫描,具体配置如下:
<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.pojovalue>
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;
// 测试spring data jpa的环境
@Test
@Transactional
@Rollback(value = false)
public void testInsertUser(){
Users users=new Users();
users.setUserName("李四");
users.setUserAge(23);
usersDao.save(users);
}
//测试usersDao注入的到底是什么
@Test
public void test01(){
System.out.println(usersDao);
//org.springframework.data.jpa.repository.support.SimpleJpaRepository@5f3b84bd
System.out.println(usersDao.getClass());
//class com.sun.proxy.$Proxy59
//会发现注入的是一个代理对象
System.out.println("======");
JpaRepositoryFactory factory=new JpaRepositoryFactory(entityManager);
//factory.getRepository()方法可以帮助我们为接口生成实现类,而这个实现类是SimpleJpaRepository的代理对象
//接口必须要继承Repository接口
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(){
//判断相等的条件有三种方式
//1.什么都不写 2.is 3.equal
List<Users> list= userDao02.findByUserNameIs("张三");
System.out.println(list);
}
//根据用户姓名Like处理
@Test
@Transactional
@Rollback(value = false)
public void test03(){
List<Users> list= this.userDao02.findByUserNameLike("张%");
System.out.println(list);
}
//查询名称为王五,并且他的年龄大于等于20岁
@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注解
// 可以用?index,index从1开始来传参。如:from Users where userName=?1
//也可以用下面这种@param来传参数
@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注解查询SQL语句
//要开启nativeQuery为true
@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注解进行数据更新
//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;
//继承自PagingAndSortingRepository这个接口,并且这个接口里面要传入一个泛型,泛型的一个个参数是要 *** 作的表对应的实体类,第二个参数为表主键的数据类型
public interface UserDao01 extends PagingAndSortingRepository<Users,Integer> {
}
如果你比较懒,不想再创建一个人接口,也没有关系,因为我们之前用的UsersDao就是就继承自JPArepository接口,而JPArepository接口又继承了PagingAndSortingRepository这个接口,也就是说你可以用之前得Dao就可以了。
然后回到我们的测试代码当中。编写如下的测试方法来学习这个接口的相关 *** 作。
比如说我要对数据表中所有的数据做分页处理:
/**
* 分页
*/
@Test
@Transactional
@Rollback(value = false)
public void test12(){
//这里注意,Pageable是接口,我们不能直接new这个接口,而应该new他的接口实现类PageRequest。
Integer page=0;// page:当前页得索引,丛林开始
Integer size=3;// size:每页显示几条数据,这里是三条
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构造方法可以传入两个参数
//第一个参数direction:排序规则
//第二个参数properties:指定做排序的属性
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对象封装了排序规则以及指定的排序字段(用对象的属性名来表示)
//Sort构造方法可以传入两个参数
//第一个参数direction:排序规则
//第二个参数properties:指定做排序的属性
//Order的构造参数与Sort的一样
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;
//继承自JpaSpecificationExecutor接口,这个接口传入一个泛型(要查询的表对应的实体类)。
//这个接口不能单独使用,需要配合着jpa中的其他接口一起使用
@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>() {
/**
*
* @param root :根对象。封装了查询条件的对象
* @param query :定义了基本的查询,一般不使用
* @param criteriaBuilder :创建一个查询的条件
* @return Predicate:定义了查询条件
*/
@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对象
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 spec=new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.like(root.get("userName").as(String.class),"张%");
}
};
//排序
Sort sort=Sort.by(Sort.Direction.DESC,"userAge");
List 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;
//dao具体要 *** 作那个表,就对那个表的实体类添加CascadeType
//通过cascade = CascadeType.PERSIST来进行级联 *** 作,使Users表在更新的同时也能更新到Roles表
@OneToOne(cascade = CascadeType.PERSIST)
//JoinColumn的作用就是维护一个外键
@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的作用:
//它可以写在任一的多对多关系的实体中,配置中间表
//joinColumns作用:建立当前表在中间表中的外键字段
@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("超级管理员");
//创建菜单对象
//比如xxx管理平台,他下面会有用户管理等
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注解标注实体类,必需
@Entity
//@Table注解:对应数据库中的表, 必须, name=表名, Indexes是声明表里的索引, columnList是索引的列, 同时声明此索引列是否唯一, 默认false
@Table(name="student",indexes = {@Index(name="id",columnList = "id",unique = true),@Index(name = "name",columnList = "name",unique = true)})
public class Student {
@Id //id用于指明主键
//@GeneratedValue: 表明是否自动生成, 必须, strategy也是必写, 指明主键生成策略, 默认是Oracle
@GeneratedValue(strategy = GenerationType.IDENTITY)
// @Column: 对应数据库列名
@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);
}
}
到这里基本的整合与使用都介绍完了。如果以后我遇到其他的用法和知识点我再回来添加。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)