前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring全家桶之SpringData——Spring Data JPA

Spring全家桶之SpringData——Spring Data JPA

作者头像
时间静止不是简史
发布2020-07-24 17:03:06
3.7K0
发布2020-07-24 17:03:06
举报
文章被收录于专栏:Java探索之路Java探索之路

Spring Data JPA

  • 一、介绍
    • 常用注解
      • 实体类中
      • 测试类中
    • 相关术语
  • 二、实战应用 :搭建Spring Data JPA项目
    • 介绍
    • 步骤
      • 1. 导入jar 两个核心jar 加上3个sl4j的jar
      • 2. 在配置文件中开启Spring Data JPA的命名空间以及它的约束
      • 3. 在配置文件中添加Spring Data JPA的配置
      • 4. 让dao接口继承 JpaRepository接口
      • 5 进行测试
  • 三、Spring Data JPA 的接口继承结构
  • 四、Spring Data JPA 的运行原理
  • 五、Repository接口
    • 基于方法名称命名规则查询
      • 等值查询
      • like查询
      • 多条件查询
      • 其他类型的查询
    • 基于@query注解的查询
      • 等值查询
      • like查询
      • 多条件查询
      • 更新操作
  • 六、CrudRepository接口
    • 创建接口
    • 测试代码
  • 七、PagingAndSortingRepository接口
    • 创建接口
    • 测试代码
      • 分页处理
      • 排序处理
  • 八、JpaRepository 接口
    • 创建接口
    • 测试代码
  • 九、JpaSpecificationExecutor接口
    • 创建接口
    • 测试代码
      • 单条件查询
      • 多条件查询(and)
      • 多条件查询(and/or另一种写法)
      • 带条件分页查询
      • 带条件的排序查询
      • 带条件与排序的分页查询
  • 十、用户自定义Repository接口
    • 创建接口
    • 创建实现类
    • 使用接口
    • 编写测试代码
  • 十一、关系映射操作
    • 一对一的关联操作
      • 创建用户实体
      • 创建角色实体
      • 测试代码
    • 一对多的关联操作
      • 创建用户实体
      • 创建角色实体
      • 测试代码
    • 多对多的关联操作
      • 创建菜单实体
      • 创建角色实体
      • 创建接口
      • 测试代码

一、介绍

Spring Data JPA:Spring Data JPA 是spring data 项目下的一个模块。提供了一套基于JPA标准操作数据库的简化方案。底层默认的是依赖Hibernate JPA 来实现的。 Spring Data JPA 的技术特点:我们只需要定义接口并继承Spring Data JPA 中所提供的接口就可以了。不需要编写接口实现类。 SpringDataJPA官网

常用注解

实体类中

注解名称

作用

@Entity

表示当前类是实体类

@Table(name=“t_roles”)

表示开启正向工程,运行后会自动创建 t_roles这个表

@Id

表示当前属性作为该表的主键

@GeneratedValue(strategy=GenerationType.IDENTITY)

配合@Id一起使用,表示令当前主键自增

@Column(name=“userid”)

表示将当前属性添加到数据库表中 ,列名为userid

@OneToOne(mappedBy=“roles”)

表示当前roles对象与另一张表中(@JoinColumn)相等的数据

@OneToOne(cascade=CascadeType.PERSIST)

创建级联操作 ,一般在存在外键的那个列 ,一般与@JoinColumn连用

@OneToMany()

指一对多关系 .cascade=CascadeType.PERSIST 表示对该外键开启级联操作 ,mappedBy 表示被该外键对象属性引用

@ManyToMany()

指多对多关系 .cascade=CascadeType.PERSIST 表示对该外键开启级联操作 mappedBy 表示被该外键对象属性引用fetch=FetchType.EAGER : 放弃延迟加载,解决多对多查询时,查询闻不到对象的问题

@JoinColumn(name=“roles_id”)

在本表创建roles_id 这个栏位开启外键并维护这个外键一般与级联操作的属性同时出现

@JoinTables

映射中间表信息,配置在哪一侧都可以,多对多joinColumns: 当前表主键所关联的中间表中的外键字段inverseJoinColumns :建立另一张表在中间表中的外键字段

举例:

@JoinTable(name=“t_roles_menus”,joinColumns=@JoinColumn(name=“role_id”),inverseJoinColumns=@JoinColumn(name=“menu_id”))

补充 :

正向工程: 通过实体类和查询方法自动创建数据库表 如Hibernate与Hibernate Jpa 逆向工程: 通过数据库表自动创建对应的实体类以及查询方法 逆向工程的使用

测试类中

注解名称

作用

@RunWith(SpringJUnit4ClassRunner.class)

表示运行当前类时 ,同时调用SpringJUnit4ClassRunner类(测试类)

@ContextConfiguration(“classpath:applicationContext.xml”)

表示运行该类时 ,同时扫描的的配置文件

@Test

表示当前方法开启Junit调试

@Transactional

声明开启事务 , 对于事务提交方式默认的是回滚。

@Rollback(false)

取消自动回滚

相关术语

持久化

持久化是将程序数据在持久状态和瞬时状态间转换的机制。通俗的讲,就是瞬时数据(比如内存中的数据,是不能永久保存的)持久化为持久数据(比如持久化至数据库中,能够长久保存)。

持久层

所谓“持久层”,多指Dao层或者Mapper层 ,也就是在系统逻辑层面上,专注于实现数据持久化的一个相对独立的领域(Domain),是把数据保存到可掉电式存储设备中。持久层是负责向(或者从)一个或者多个数据存储器中存储(或者获取)数据的一组类和组件。

持久化状态

持久化状态对象表示在数据库中有对应id的记录,同时在session缓存中也存在对应ID的对象 ,可以随时对进行增删改查操作操作

Hibernate三种状态

介绍

itransient 临时状态

类似:没有编号的公司临时工说明:临时状态表示在数据库中没有对应id的记录,同时在session缓存中也不存对应ID的对象

persistent 持久化状态

类似:是有编号的公司正式员工说明:持久化对象表示在数据库中有对应id的记录,同时在session缓存中也存在对应ID的对象;

detached 游离状态

类似:休假中的公司正式员工(与公司失去联系)说明:游离状态表示在数据库中有对应ID的记录,但在session缓存中不存在对应ID的对象;

二、实战应用 :搭建Spring Data JPA项目

介绍

Spring Data JPA 实现无需在dao层实现类书写代码即可实现对数据库的操作 使用的查询语言是 HQL语言 本项目是基于 Hibernate Jpa项目上构建 ,Hibernate Jpa查看上篇博文

步骤

1. 导入jar 两个核心jar 加上3个sl4j的jar

至此所有jar包如下

代码语言:javascript
复制
antlr-2.7.7.jar
aopalliance.jar
aspectjrt.jar
aspectjweaver.jar
c3p0-0.9.2.1.jar
commons-logging-1.1.1.jar
dom4j-1.6.1.jar
geronimo-jta_1.1_spec-1.1.1.jar
hibernate-c3p0-5.0.7.Final.jar
hibernate-commons-annotations-5.0.1.Final.jar
hibernate-core-5.0.7.Final.jar
hibernate-entitymanager-5.0.7.Final.jar
hibernate-jpa-2.1-api-1.0.0.Final.jar
jandex-2.0.0.Final.jar
javassist-3.18.1-GA.jar
jboss-logging-3.3.0.Final.jar
log4j-1.2.16.jar
mchange-commons-java-0.2.3.4.jar
mysql-connector-java-5.1.7-bin.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.7.2.jar
spring-aop-4.2.0.RELEASE.jar
spring-aspects-4.2.0.RELEASE.jar
spring-beans-4.2.0.RELEASE.jar
spring-context-4.2.0.RELEASE.jar
spring-core-4.2.0.RELEASE.jar
spring-data-commons-1.11.0.RELEASE.jar
spring-data-jpa-1.9.0.RELEASE.jar
spring-expression-4.2.0.RELEASE.jar
spring-jdbc-4.2.0.RELEASE.jar
spring-orm-4.2.0.RELEASE.jar
spring-test-4.2.0.RELEASE.jar
spring-tx-4.2.0.RELEASE.jar

2. 在配置文件中开启Spring Data JPA的命名空间以及它的约束

代码语言:javascript
复制
xmlns:jpa="http://www.springframework.org/schema/data/jpa"

http://www.springframework.org/schema/data/jpa 
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd

3. 在配置文件中添加Spring Data JPA的配置

代码语言:javascript
复制
	<!-- Spring Data JPA 的配置 --> 
	<!-- base-package:扫描 dao 接口所在的包 --> 
	<jpa:repositories base-package="ah.szxy.dao"/>

至此,完整的配置文件如下

代码语言:javascript
复制
<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

	<!-- 配置读取properties工具类 -->
	<context:property-placeholder
		location="classpath:.properties" />

	<!-- 配置c3p0数据库连接池 -->
	<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>

	<!-- Spring 整合JPA 配置EntityManagerFactory -->
	<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">
				<!-- hibernate 相关的属性的注入 -->
				<!-- 配置数据库类型 -->
				<property name="database" value="MYSQL" />
				<!-- 正向工程自动创建表 -->
				<property name="generateDdl" value="true" />
				<!-- 显示执行的SQL -->
				<property name="showSql" value="true" />
			</bean>
		</property>
		<!-- 扫描实体的包 -->
		<property name="packagesToScan">
			<list>
				<value>ah.szxy.pojo</value>
			</list>
		</property>
	</bean>
	<!-- 配置Hibernate 的事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	

	<!-- 配置开启注解事务处理 -->
	<tx:annotation-driven
		transaction-manager="transactionManager" />

	<!-- 配置springIOC的注解扫描 -->
	<context:component-scan base-package="ah.szxy" />

	<!-- Spring Data JPA 的配置 --> 
	<!-- base-package:扫描 dao 接口所在的包 --> 
	<jpa:repositories base-package="ah.szxy.dao"/>
</beans>

db.properties(数据库连接参数)

代码语言:javascript
复制
jdbc.url=jdbc:mysql://localhost:3306/springdata
jdbc.driver.class=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=root

实体类不变 ,代码如下

代码语言:javascript
复制
package ah.szxy.pojo;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@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;

	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;
	}

	@Override
	public String toString() {
		return "Users [userid=" + userid + ", username=" + username + ", userage=" + userage + "]";
	}

	public Users(Integer userid, String username, Integer userage) {
		super();
		this.userid = userid;
		this.username = username;
		this.userage = userage;
	}

	public Users() {
		super();
	}
	
	
}

4. 让dao接口继承 JpaRepository接口

JpaRepository<pojo.class ,主键类型> : 接口中没有方法 ,没有接口实现类 ,接口内置 因为是自动生成的接口以及实现类 ,所以只能进行简单的数据库操作 可以调用的超类的方法如下

接口类

代码语言:javascript
复制
package ah.szxy.dao;


import org.springframework.data.jpa.repository.JpaRepository;

import ah.szxy.pojo.Users;

// JpaRepository<实体类, 主键类型>
public interface UserDao extends  JpaRepository<Users, Integer>{
	
}

5 进行测试

测试类

代码语言:javascript
复制
package ah.szxy.test;

import java.util.List;

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 ah.szxy.dao.UserDao;
import ah.szxy.pojo.Users;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestHibernate {

	@Autowired
	private UserDao userDao;

	/**
	 * 添加用户
	 */
	@Test
	@Transactional // 在测试类对于事务提交方式默认的是回滚。
	@Rollback(false) // 取消自动回滚
	public void testInsertUsers() {
		Users users = new Users();
		users.setUserage(23);
		users.setUsername("jpa");
		this.userDao.save(users);
	}


}

三、Spring Data JPA 的接口继承结构

四、Spring Data JPA 的运行原理

通过运行测试类 ,来简单的帮我们理解一下其运行原理

代码语言:javascript
复制
@PersistenceContext(name="entityManagerFactory")
	private EntityManager em;
	@Test
	public void test1(){
	//org.springframework.data.jpa.repository.support.SimpleJpaRepository@fba8bf
	//System.out.println(this.usersDao);
	//class com.sun.proxy.$Proxy29 代理对象是基于JDK 的动态代理方式创建的
	//System.out.println(this.usersDao.getClass());
	JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
	//getRepository(UsersDao.class);可以帮助我们为接口生成实现类。而这个实现类是SimpleJpaRepository 的对象
	//要求:该接口必须要是继承Repository 接口
	UserDao ud = factory.getRepository(UserDao.class);
	System.out.println(ud);//org.springframework.data.jpa.repository.support.SimpleJpaRepository@5fad41be
	System.out.println(ud.getClass());//class com.sun.proxy.$Proxy30

	}

从下面起 ,开始介绍SpringData Jpa的五个接口 ,使我们掌握其相关的用法 ,更加自如的进行数据库的crud操作

五、Repository接口

Repository 接口是Spring Data JPA 中为我们提供的所有接口中的顶层接口 Repository 提供了两种查询方式的支持 1)基于方法名称命名规则查询 2)基于@Query 注解查询

使用前提

  • dao层接口要继承Repository<实体类, 主键类型>接口
  • 导入 org.springframework.data.repository.Repository; //有重名jar

基于方法名称命名规则查询

规则 :findBy(关键字)+(属性名称的首字母大小写) +查询条件(首字母大写)

等值查询

接口层

代码语言:javascript
复制
/**
	 * 等值查询
	 * @param string
	 * @return
	 */
	List<Users> findByUsernameIs(String name);

测试类层

代码语言:javascript
复制
/**
	 * 需求 :使用用户名做查询条件
	 */
	@Test
	public void test1(){
		/**
		* 判断相等的条件,有三种表示方式 (  需要首先在接口中声明 )
		* 1  什么都不写,默认的就是做相等判断
		* 2 Is
		* 3 Equal
		*/
		List<Users> list = this.userDao.findByUsernameIs("宿州学院");
		for(Users users:list) {
			
			System.out.println(users);
		}
	}

查询结果

like查询

代码语言:javascript
复制
/**
	 * like关键字查询
	 * @param string
	 * @return
	 */
	List<Users> findByUsernameLike(String name);

测试类层

代码语言:javascript
复制
	/**
	* 需求:根据用户姓名做Like 处理
	* Like:条件关键字
	*/
	@Test
	public void test2() {
		
		List<Users> list = this.userDao.findByUsernameLike("宿州%");
		for(Users users:list) {
			
			System.out.println(users);			
		}
	}

查询结果

多条件查询

接口层

代码语言:javascript
复制
	/**
	 * 多条件查询 :名称等于并且年龄大于..
	 * @param name
	 * @param age
	 * @return
	 */
	List<Users> findByUsernameAndUserageGreaterThanEqual(String name,Integer age);

测试类层

代码语言:javascript
复制
/**
	* 需求:查询名称为宿州学院,并且他的年龄大于等于22 岁
	*/
	@Test
	public void test3() {
		
		List<Users> list = this.userDao.findByUsernameAndUserageGreaterThanEqual("宿州学院", 25);
		for(Users users:list) {
			
			System.out.println(users);			
		}
	}

查询结果

其他类型的查询

关键字 ———— 方法命名 ———— sql where子句

基于@query注解的查询

@Query 注解查询 , 根据这个注解改写上面的查询方法

名称书写无要求 ,本人这样写只是方便对比

接口层和查询结果层同上 ,故省略

等值查询

接口层

代码语言:javascript
复制
	@Query(value="from Users where username =?")
	List<Users> queryByUsername(String name);

like查询

接口层

代码语言:javascript
复制
	@Query("from Users where username like ?")
	List<Users> queryByUsernameLike(String keywords);

多条件查询

接口层

代码语言:javascript
复制
	@Query("from Users where username =? and userage >=?")
	List<Users> queryByUsernameAndUserageGreaterThanEqual(String username,Integer userage);

更新操作

@Modifying //标识当前语句是一个更新操作

接口层

代码语言:javascript
复制
/**
	 * @Modifying    //标识当前语句是一个更新操作
	 * @param userage
	 * @param userid
	 */
	@Query("update Users set userage =? where userid =?")
	@Modifying    
	void updateUserageByUserid(Integer userage,Integer userid);

六、CrudRepository接口

继承了该接口 ,无需实现类即可完成如下操作

支持增删改查及其批量处理

创建接口

代码语言:javascript
复制
package ah.szxy.dao;

import org.springframework.data.repository.CrudRepository;
import ah.szxy.pojo.Users;

public interface UserDao extends CrudRepository<Users, Integer>{
	
}

测试代码

更新数据方式二——在查询后直接修改 ,因为在查询后这个对象会处于持久化状态

所以需要开启需要关闭事务回滚

代码语言:javascript
复制
package ah.szxy.test;

import java.util.ArrayList;
import java.util.List;

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 ah.szxy.dao.UserDao;
import ah.szxy.pojo.Users;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestCrudRepository {

	@Autowired
	private UserDao userDao;

	/**
	 * 插入数据
	 */
	@Test
	public void test1() {

		Users user = new Users();
		user.setUsername("两仪式");
		user.setUserage(18);
		this.userDao.save(user);
	}

	/**
	 * 批量插入数据
	 */
	@Test
	public void test2() {

		Users user = new Users();
		user.setUsername("阿尔利亚潘多拉贡");
		user.setUserage(16);

		Users user2 = new Users();
		user2.setUsername("卫宫士郎");
		user2.setUserage(18);

		ArrayList<Users> list = new ArrayList<Users>();
		list.add(user);
		list.add(user2);
		this.userDao.save(list);
	}

	/**
	 * 根据id查询单条数据
	 */
	@Test
	public void test3() {
		Users user = this.userDao.findOne(16);
		System.out.println(user);
	}

	/**
	 * 查询全部数据
	 * 主要对返回值做强转,因为返回的是Iterable<T>
	 */
	@Test
	public void test4() {
		List<Users> list = (List<Users>) this.userDao.findAll();
		for (Users users : list) {
			System.out.println(users);
		}
	}

	/**
	 * 删除数据
	 */
	@Test
	public void test5() {
		this.userDao.delete(8);
	}

	/**
	 * 更新数据方式一
	 *先查询然后再插入
	 */
	@Test
	public void test6() {
		Users user = this.userDao.findOne(12);
		user.setUsername("王小红");
		this.userDao.save(user);
	}
	
	/**
	* 更新数据方式二
	* 在查询后直接修改 ,因为在查询后这个对象会处于持久化状态
	* 需要注意的是需要加上事务注解
	*/
	@Test
	@Transactional
	@Rollback(false)
	public void test7(){
		Users user = this.userDao.findOne(12);//持久化状态的
		user.setUsername("王小小");
		}
 	
}

七、PagingAndSortingRepository接口

见名知意 , 主要用于处理分页和排序

创建接口

代码语言:javascript
复制
public interface UserDao extends PagingAndSortingRepository<Users, Integer>{
	
}

测试代码

分页处理

注意导的包是否和如下一致!!!

代码语言:javascript
复制
package ah.szxy.test;

import java.util.List;

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.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import ah.szxy.dao.UserDao;
import ah.szxy.pojo.Users;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestCrudRepository {

	@Autowired
	private UserDao userDao;

	/**
	 * 分页 page: 当前页的索引。注意索引都是从0 开始的。 size: 每页显示3 条数据
	 * 导入data.domain.*;
	 * PagingAndSortingRepository接口不能自己写查询条件进行分页 不过可以自己在定义一个dao接口以及实现。可以对自己的需求做扩展
	 */
	@Test
	public void test() {

		int page = 0;
		int size = 3;
		Pageable pageable = new PageRequest(page, size);
		Page<Users> p = this.userDao.findAll(pageable);
		System.out.println("数据的总条数 : " + p.getTotalElements());
		System.out.println("总页数 :" + p.getTotalPages());
		List<Users> list = p.getContent();
		for (Users users : list) {
			System.out.println(users);
		}
	}

排序处理

代码语言:javascript
复制
/**
	 * 对单列做排序处理
	 * 
	 * Sort:该对象封装了排序规则以及指定的排序字段(对象的属性来表示) direction:排序规则 properties:指定做排序的属性
	 */
	@Test
	public void test2() {

		Sort sort = new Sort(Direction.DESC, "userid");
		List<Users> list = (List<Users>) this.userDao.findAll(sort);
		for (Users users : list) {
			System.out.println(users);
		}
	}

	/**
	 * 多列的排序处理
	 */
	@Test
	public void test3() {
		// Sort:该对象封装了排序规则以及指定的排序字段(对象的属性来表示)
		// direction:排序规则
		// properties:指定做排序的属性
		Order order1 = new Order(Direction.DESC, "userid");
		Order order2 = new Order(Direction.ASC, "userage");
		Sort sort = new Sort(order1, order2);
		List<Users> list = (List<Users>) this.userDao.findAll(sort);
		for (Users users : list) {
			System.out.println(users);
		}
	}

八、JpaRepository 接口

JpaRepository 接口是我们开发时使用的最多的接口。其特点是可以帮助我们将其他接口的方法的返回值做适配处理。可以使得我们在开发时更方便的使用对数据库进行DML操作方法。

创建接口

代码语言:javascript
复制
public interface UserDao extends JpaRepository<Users, Integer>{
	
}

测试代码

无需强转 ,对比CrudRepository , 故一般会使用这个接口进行增删改查操作

代码语言:javascript
复制
package ah.szxy.test;

import java.util.List;

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.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import ah.szxy.dao.UserDao;
import ah.szxy.pojo.Users;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestCrudRepository {

	@Autowired
	private UserDao userDao;
	
	/**
	 * 查询所有数据
	 * 无需强转 ,对比CrudRepository ,故一般会使用这个接口进行增删改查操作
	 */
	@Test
	public void test() {
		
		List<Users> list = this.userDao.findAll();
		for(Users users:list) {
			System.out.println(users);
		}
	}
}

九、JpaSpecificationExecutor接口

创建接口

JpaSpecificationExecutor:不能单独使用,需要配合 jpa 中的其他接口一起使用 , 可以完成多条件查询,并且支持带条件和排序的分页与查询

代码语言:javascript
复制
/**
 * JpaSpecificationExecutor 接口
 * 注意:JpaSpecificationExecutor<Users>:不能单独使用,需要配合着jpa 中的 其他接口一起使用
 * 
 * @author chy
 */
public interface UserDao extends JpaRepository<Users, Integer>, JpaSpecificationExecutor<Users> {

}

测试代码

单条件查询

代码语言:javascript
复制
package ah.szxy.test;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

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.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import ah.szxy.dao.UserDao;
import ah.szxy.pojo.Users;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestCrudRepository {

	@Autowired
	private UserDao userDao;

	/**
	 * 需求:根据用户姓名查询数据
	 */
	@Test
	public void test1() {
		//这里创建了一个匿名内部类,完成了查询条件的封装
		Specification<Users> spec = new Specification<Users>() {
			/**
			 * 那条件查询时还用or或者其他条件怎么办
			 * 使用什么条件可以直接使用CriteriaBuilder对象条用对应的方法
			 * @param  Root<Users> root:根对象。封装了查询条件的对象
			 * @param   CriteriaQuery<?> query:定义了一个基本的查询.一般不使用
			 * @param CriteriaBuilder cb:创建一个查询条件
			 * @return Predicate:定义了查询条件
			 */
			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate pre = cb.equal(root.get("username"), "卫宫士郎");
				return pre;
			}
		};
		List<Users> list = this.userDao.findAll(spec);
		for (Users users : list) {
			System.out.println(users);
		}
	}


}

多条件查询(and)

代码语言:javascript
复制
/**
	* 多条件查询方式一
	* 需求:使用用户姓名以及年龄查询数据
	*/
	@Test
	public void test2() {
		
		Specification<Users> spec = new Specification<Users>() {

			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				//利用list封装查询条件
				ArrayList<Predicate> list = new ArrayList<Predicate>();
				list.add(cb.equal(root.get("username") , "卫宫士郎"));
				list.add(cb.equal(root.get("userage") , 18));
				//此时这两个条件没有关系 ,通过cd再为其加上关系
				Predicate[] arr=new Predicate[list.size()];
				return cb.and(list.toArray(arr));
			}
		};
		
		List<Users> users = this.userDao.findAll(spec);
		System.out.println(users);
	}

多条件查询(and/or另一种写法)

代码语言:javascript
复制
	/**
	* 多条件查询方式二
	* 需求:使用用户姓名或年龄查询数据
	*/
	@Test
	public void test3() {
		Specification<Users> spec = new Specification<Users>() {
			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
			
				return cb.or(cb.equal(root.get("username"), "宿州学院"),cb.equal(root.get("userage"), 23));
				
				//or 和and一起使用
//				return cb.and((cb.or(cb.equal(root.get("username"), "宿州学院"),cb.equal(root.get("userage"), 23)))
//						,cb.equal(root.get("userid"), 4));
			}
		};
		
		List<Users> users = this.userDao.findAll(spec);
		for (Users users2 : users) {
			System.out.println(users2);
		}
	}

带条件分页查询

代码语言:javascript
复制
/**
	 * 带条件的分页查询
	 * 需求:查询宿州姓用户,并且做分页处理
	 */
	@Test
	public void test4() {
		Specification<Users> spec = new Specification<Users>() {

			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

				return cb.like(root.get("username").as(String.class ),"宿州%");
			}
		};
		
		Pageable pageable=new PageRequest(0, 2);
		Page<Users> page = this.userDao.findAll(spec, pageable);
		
		System.out.println("总条数 : "+page.getTotalElements());
		System.out.println("总页数 : "+page.getTotalPages());
		for (Users users : page) {
			System.out.println(users);
		}
	}

带条件的排序查询

代码语言:javascript
复制
/**
	 * 带条件的排序查询
	* 需求:查询数据库中存在宿州的用户,并且根据用户id 做倒序排序
	*/
	@Test
	public void test5() {
		Specification<Users> spec = new Specification<Users>() {

			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

				return cb.like(root.get("username").as(String.class ),"宿州%");
			}
		};
		
		Sort sort=new Sort(Direction.DESC,"userage");
		List<Users> list = this.userDao.findAll(spec, sort);
		for (Users users : list) {
			System.out.println(users);
		}
	}

带条件与排序的分页查询

代码语言:javascript
复制
/**
	 * 带条件与排序的分页查询
	 * 使用的是分页查询的方法
	* 需求:查询数据库中存在宿州的用户,做分页处理,并且根据用户id 做倒序排序
	*/
	@Test
	public void Test6() {
		//1. 定义排序
		Sort sort=new Sort(Direction.DESC,"userid");
		Pageable pageable=new PageRequest(0, 2, sort);
		//2.定义分页
		Specification<Users> spec = new Specification<Users>() {
			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {			
				return cb.like(root.get("username").as(String.class), "宿州%");
			}
			
		};
		Page<Users> page = this.userDao.findAll(spec, pageable);
		System.out.println("总条数 : "+page.getTotalElements());
		System.out.println("总页数 : "+page.getTotalPages());
		for (Users users : page) {
			System.out.println(users);
		}
	}

十、用户自定义Repository接口

用户通过自定义接口来定义一些业务逻辑,通过接口的实现类实现, 然后利用Dao层接口继承我们所编写的自定义Repository接口. 测试类可以通过注入Dao层接口来调用我们在自定义接口中定义的方法

创建接口

代码语言:javascript
复制
package ah.szxy.dao;

import ah.szxy.pojo.Users;

public interface UserSelfRepository {
	
	public Users findUserById(Integer userid);
}

创建实现类

代码语言:javascript
复制
package ah.szxy.dao;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import ah.szxy.pojo.Users;

public class UserDaoImpl implements UserSelfRepository {
	
	@PersistenceContext(name="entityManagerFactory")
	private EntityManager em;
	
	@Override
	public Users findUserById(Integer userid) {

		System.out.println("MyRepository......");
		return this.em.find(Users.class, userid);
	}

}

使用接口

代码语言:javascript
复制
package ah.szxy.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import ah.szxy.pojo.Users;

/**
 * 用户自定义接口实现
 * 需要在这里继承自己编写好的接口
 * @author chy
 */
public interface UserDao extends JpaRepository<Users,Integer>,
			JpaSpecificationExecutor<Users>,UserSelfRepository{

}

编写测试代码

代码语言:javascript
复制
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserSelfRepository {

	@Autowired
	private UserDao userDao;

	/**
	 * 根据用户id查询用户信息
	 */
	@Test
	public void test1() {
	
		Users user = this.userDao.findUserById(9);
		System.out.println(user);
	}	
}

十一、关系映射操作

一对一的关联操作

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

创建用户实体

添加用于关联的引用对象的属性 ,并添加相应的取值赋值方法

代码语言:javascript
复制
package ah.szxy.pojo;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@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="roles_id") //创建并维护这个外键
	private Roles roles;
	
	
	
	
	public Roles getRoles() {
		return roles;
	}

	public void setRoles(Roles roles) {
		this.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;
	}

	@Override
	public String toString() {
		return "Users [userid=" + userid + ", username=" + username + ", userage=" + userage + "]";
	}

	public Users(Integer userid, String username, Integer userage) {
		super();
		this.userid = userid;
		this.username = username;
		this.userage = userage;
	}

	public Users() {
		super();
	}
	
	
}

创建角色实体

添加用于关联的引用对象的属性 ,并添加相应的取值赋值方法

代码语言:javascript
复制
@Entity
@Table(name="t_roles")  //表示开启正向工程,运行后会自动常见t_roles这个表
public class Roles {
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)  //自增长
	@Column
	private Integer roleId;
	@Column
	private String roleName;
	
	@OneToOne(mappedBy="roles")
	private Users users;
	
	
	
	public Users getUsers() {
		return users;
	}
	public void setUsers(Users users) {
		this.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;
	}
	@Override
	public String toString() {
		return "Roles [roleId=" + roleId + ", roleName=" + roleName + "]";
	}
	public Roles(Integer roleId, String roleName) {
		super();
		this.roleId = roleId;
		this.roleName = roleName;
	}
	public Roles() {
		super();
	}
	
	
	
}

测试代码

代码语言:javascript
复制
package ah.szxy.test;

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;

import ah.szxy.dao.UserDao;
import ah.szxy.pojo.Roles;
import ah.szxy.pojo.Users;

/**
 * 一对一关系测试
 * 
 * @author chy
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestOneToOne {

	@Autowired
	private UserDao userDao;

	@Test
	public void test1() {
		// 创建角色
		Roles roles = new Roles();
		roles.setRoleName("管理员");
		// 创建用户
		Users users = new Users();
		users.setUserage(37);
		users.setUsername("赵小雷");
		// 建立关系
		users.setRoles(roles);
		roles.setUsers(users);
		// 保存数据
		this.userDao.save(users);
	}

	/**
	 * 根据用户ID 查询用户,同时查询用户角色
	 */
	@Test
	public void test2() {
		Users users = this.userDao.findOne(20);
		System.out.println("用户信息:" + users);
		Roles roles = users.getRoles();
		System.out.println(roles);
	}
}

运行结果

一对多的关联操作

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

角色:一方

用户:多方(添加外键)

创建用户实体

需要在添加外键的那一开启级联操作 ,防止数据插入时出现异常

@ManyToOne(cascade=CascadeType.PERSIST)

@JoinColumn(name=“roles_id”) //创个栏位开启外键并维护这个外键

代码语言:javascript
复制
package ah.szxy.pojo;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@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="roles_id") //创个栏位开启外键并维护这个外键
	private Roles roles;
	 
	
//其他方法省略
}

创建角色实体

注意在toString() 不能打印Users的值, 因为在测试方法中 Roles的值本来就是通过Users获取的,

//但是我们又无法通过Roles 获取Users 因为他们不是多对多的关系

用户表中添加了 @ManyToOne()

角色表中添加了 @OneToMany()

代码语言:javascript
复制
package ah.szxy.pojo;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name="t_roles")  //表示开启正向工程,运行后会自动常见t_roles这个表
public class Roles {
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)  //自增长
	@Column
	private Integer roleId;
	@Column
	private String roleName;
	
	
	@OneToMany(mappedBy="roles")
	private Set<Users> users=new HashSet<Users>();//用set集合来接收外键和主键相同的多个用户
	
	
	//其他方法省略 ,注意在toString() 不能打印Users的值,因为在测试方法中 Roles的值本来就是通过Users获取的,
	//但是我们又无法通过Roles 获取Users 因为他们不是多对多的关系
	
}

测试代码

代码语言:javascript
复制
/**
 * 测试一对多关系
 * 
 * @author chy
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestOneToMany {

	@Autowired
	private UserDao userDao;

	/**
	 * 添加用户同时添加角色
	 */
	@Test
	public void test1() {
		// 创建角色
		Roles roles = new Roles();
		roles.setRoleName("战斗天使");
		// 创建用户
		Users users = new Users();
		users.setUsername("阿丽塔");
		users.setUserage(24);
		// 建立关系
		roles.getUsers().add(users); // 为users这个set集合添加属性
		users.setRoles(roles); // 为user保存roles相关信息 ,如外键roles_id
		// 保存数据
		this.userDao.save(users);
	}

	/**
	 * 根据用户ID 查询用户信息,同时查询角色
	 */
	@Test
	public void test2() {
		Users users = this.userDao.findOne(23);
		System.out.println("用户姓名:" + users.getUsername());
		Roles roles = users.getRoles();
		System.out.println(roles);
	}

}

多对多的关联操作

需求:一个角色可以拥有多个菜单,一个菜单可以分配多个角色。多对多的关联关系

角色:多方(哪一方都可以创建外键 ,先在这里创建外键)

菜单:多方

创建菜单实体

代码语言:javascript
复制
@Entity
@Table(name="t_menus")
public class Menus {
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="menuId")
	private Integer menuId;
	@Column(name="menuName")
	private String menuName;
	@Column(name="menuUrl")
	private String menuUrl;
	@Column(name="fatherId")
	private Integer fatherId;
	
	@ManyToMany(mappedBy="menus",fetch=FetchType.EAGER)
	private Set<Roles> roles = new HashSet<>();

//其他方法省略
	
}

创建角色实体

@ManyToMany(cascade=CascadeType.PERSIST,fetch=FetchType.EAGER)

  • FetchType.EAGER 放弃延迟加载,解决多对多查询时,查询闻不到对象的问题 ,最好两边都要加上这个属性

@JoinTable(name=“t_roles_menus”,joinColumns=@JoinColumn(name=“role_id”),inverseJoinColumns=@JoinColumn(name=“menu_id”))

  • joinColumns:建立当前表在中间表中的外键字段
  • inverseJoinColumns :建立另一张表在中间表中的外键字段
代码语言:javascript
复制
@Entity
@Table(name="t_roles")  //表示开启正向工程,运行后会自动常见t_roles这个表
public class Roles {
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)  //自增长
	@Column
	private Integer roleId;
	@Column
	private String roleName;
	
	//FetchType 放弃延迟加载,解决多对多查询时,查询闻不到对象的问题
	@ManyToMany(cascade=CascadeType.PERSIST,fetch=FetchType.EAGER)
	//@JoinTable:配置中间表信息
	//joinColumns:建立当前表在中间表中的外键字段
	//inverseJoinColumns :建立另一张表在中间表中的外键字段
	@JoinTable(name="t_roles_menus",joinColumns=@JoinColumn(name="role_id"),
		inverseJoinColumns=@JoinColumn(name="menu_id"))
	private Set<Menus> menus = new HashSet<>();
	
	//其他方法省略
	
}

创建接口

代码语言:javascript
复制
/**
 * 多对多关系的实现
 * @author chy
 *
 */
public interface RoleDao extends JpaRepository<Roles, Integer> {

}

测试代码

代码语言:javascript
复制
/**
 * 测试多对多关联操作
 * @author chy
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestManyToMany {

	@Autowired
	private RoleDao roleDao;
	
	/**
	* 添加角色同时添加菜单
	*/
	@Test
	public void test1() {
		// 创建角色
		Roles roles = new Roles();
		roles.setRoleName("超管");
		// 创建菜单
		Menus menus = new Menus();
		menus.setFatherId(-1);
		menus.setMenuName("CSND博客平台");
		menus.setMenuUrl("www.csdn.com");

		Menus menus2 = new Menus();
		menus2.setFatherId(1);
		menus2.setMenuName("博客园博客平台");
		menus2.setMenuUrl("www.cnblogs.com");

		// 添加关系
		roles.getMenus().add(menus);
		roles.getMenus().add(menus2);

		menus.getRoles().add(roles);
		menus2.getRoles().add(roles);
		// 保存数据
		this.roleDao.save(roles);
	}

	/**
	 * 查询Roles
	 */
	@Test
	public void test2() {
		Roles roles = this.roleDao.findOne(3);
		System.out.println("角色信息:" + roles);
		Set<Menus> menus = roles.getMenus();
		for (Menus menus2 : menus) {
			System.out.println("菜单信息:" + menus2);
		}
	}
}

测试结果

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-08-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring Data JPA
  • 一、介绍
    • 常用注解
      • 实体类中
      • 测试类中
    • 相关术语
    • 二、实战应用 :搭建Spring Data JPA项目
      • 介绍
        • 步骤
          • 1. 导入jar 两个核心jar 加上3个sl4j的jar
          • 2. 在配置文件中开启Spring Data JPA的命名空间以及它的约束
          • 3. 在配置文件中添加Spring Data JPA的配置
          • 4. 让dao接口继承 JpaRepository接口
          • 5 进行测试
      • 三、Spring Data JPA 的接口继承结构
      • 四、Spring Data JPA 的运行原理
      • 五、Repository接口
        • 基于方法名称命名规则查询
          • 等值查询
          • like查询
          • 多条件查询
          • 其他类型的查询
        • 基于@query注解的查询
          • 等值查询
          • like查询
          • 多条件查询
          • 更新操作
      • 六、CrudRepository接口
        • 创建接口
          • 测试代码
          • 七、PagingAndSortingRepository接口
            • 创建接口
              • 测试代码
                • 分页处理
                • 排序处理
            • 八、JpaRepository 接口
              • 创建接口
                • 测试代码
                • 九、JpaSpecificationExecutor接口
                  • 创建接口
                    • 测试代码
                      • 单条件查询
                      • 多条件查询(and)
                      • 多条件查询(and/or另一种写法)
                      • 带条件分页查询
                      • 带条件的排序查询
                      • 带条件与排序的分页查询
                  • 十、用户自定义Repository接口
                    • 创建接口
                      • 创建实现类
                        • 使用接口
                          • 编写测试代码
                          • 十一、关系映射操作
                            • 一对一的关联操作
                              • 创建用户实体
                              • 创建角色实体
                              • 测试代码
                            • 一对多的关联操作
                              • 创建用户实体
                              • 创建角色实体
                              • 测试代码
                            • 多对多的关联操作
                              • 创建菜单实体
                              • 创建角色实体
                              • 创建接口
                              • 测试代码
                          相关产品与服务
                          对象存储
                          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档