springboot整合springdata jpa全能书

news2024/9/24 21:50:13

一:spring data jpa介绍

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

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

二:springboot整合spring data jpa

1.搭建整合环境:maven工程继承springboot父工程

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.3.RELEASE</version>
</parent>

2.修改pom文件添加坐标

<!-- spring data jpa的springboot启动器 -->
<dependency>
  	<groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql -->
<dependency>
 	 <groupId>mysql</groupId>
  	<artifactId>mysql-connector-java</artifactId>
  	<version>5.1.30</version>
</dependency>
<!-- 连接池 -->
<dependency>
  	<groupId>com.alibaba</groupId>
  	<artifactId>druid</artifactId>
  	<version>1.0.9</version>
</dependency>

3.在项目中添加application.yml文件

spring:
	# 配置数据源
	datasource:
		driver-class-name: com.mysql.jdbc.Driver
		url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
		username: root
		password: root
		# 配置连接池
		type: com.alibaba.druid.pool.DruidDataSource
	# 配置jpa
	jpa:
		# 配置正向工程
		hibernate:
			ddl-auto: update
		# 配置在控制台打印sql语句
		show-sql: true

4.添加实体类

@Entity	//表示该类是实体类
@Table(name="tb_users")	//表示正向工程生成的表名为tb_users
public class User {
	@Id	//表示该字段为主键
	@GeneratedValue(strategy=GenerationType.IDENTITY)	//表示该键生成策略为自增
	@Column(name="id")	//生成的表中对应的字段为id
	private Integer id;
		
	@Column(name="username")
	private String name;	

	@Column(name="age")
	private Integer age;

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

	...}

5.编写dao接口

public interface UserRepository extends JpaRepository<User, Integer> {
}

6.在pom文件中添加测试启动器的坐标

<!-- test工具的启动器 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
</dependency>

7.创建启动类

@SpringBootApplication
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}			
}

8.编写测试代码

//JpaRepository--添加数据
@Test
public void testSave() {
    User user = new User();
    user.setName("成龙");
    user.setAge(42);
    user.setAddress("中国深圳");
    this.userRepository.save(user);
}

三:spring data jpa提供的核心接口

1.Repository接口

2.CrudRepository接口

3.PagingAndSortingRepository接口

4.JpaRepository接口

5.JpaSpecificationExecutor接口

四:Repository接口的使用

1.提供了方法名称命名查询方式

1.1编写接口

public interface UserRepositoryByName extends Repository<User, Integer> {
  	//方法名称必须遵循驼峰式命名规则。
  	//findBy(关键字)+实体属性名(首字母大写)+查询条件(首字母大写)
    public List<User> findByName(String name); 
    public List<User> findByNameAndAge(String name,Integer age);		
    public List<User> findByNameLike(String name);		
}

1.2测试代码

//Repository--方法名称命名测试
@Test	//单条件查询
public void testFindByName() {
    List<User> userList = this.userRepositoryByName.findByName("zlg");
    for (User user : userList) {
      System.out.println(user);
    }
}
@Test	//多条件查询
public void testFindByNameAndAge() {
    List<User> userList = this.userRepositoryByName.findByNameAndAge("zlg", 23);
    for (User user : userList) {
      System.out.println(user);
    }
}
@Test	//模糊查询
public void testFindByNameLike() {
    List<User> userList = this.userRepositoryByName.findByNameLike("z%");
    for (User user : userList) {
      System.out.println(user);
    }
}

2.提供了基于@Query注解的查询与更新

2.1编写接口

//Repository接口的@query注解查询
public interface UserRepositoryQueryAnnotation extends Repository<User, Integer> {
    //采用hibernate的hql语句查询(User类名,name实体属性,:name别名 对应@Param中的key)
    @Query("from User where name = :name")
    public List<User> findByNameUserHQL(@Param("name")String name);

    //采用slq语句
    @Query(value="select * from tb_users where username = ?",nativeQuery=true)
    public List<User> findByNameUserSQL(String name);	

    //更新操作
    @Query("update User set name = :name where id = :id")
    @Modifying	//需要执行一个更新操作
    public void updateUserNameById(@Param("name")String name,@Param("id")Integer id);		
}

2.2测试代码

//Repository--@Query注解测试
@Test	//hql语句查询
public void testFindByNameUserHQL() {
    List<User> userList = this.userRepositoryQueryAnnotation.findByNameUserHQL("zlg");
    for (User user : userList) {
      System.out.println(user);
    }
}
@Test	//sql语句查询
public void testFindByNameUserSQL() {
    List<User> userList = this.userRepositoryQueryAnnotation.findByNameUserSQL("成龙");
    for (User user : userList) {
      System.out.println(user);
    }
}
@Test	//修改数据
@Transactional		//@Test与@Transactional一起使用时,事务是自动回滚的
@Rollback(false)	//取消自动回滚
public void testUpdateUserNameById() {
  	this.userRepositoryQueryAnnotation.updateUserNameById("葛优", 1);;
}

五:CrudRepository接口

1.CrudRepository接口,主要是完成一些增删改查操作。CrudRepository接口继承Repository接口。

2.编写接口

//CrudRepository接口
public interface UserRepositoryCrudRepository extends CrudRepository<User, Integer> {
}

3.测试代码

//CrudRepository--测试
@Test	//添加数据
public void testCrudRepositorySave() {
    User user = new User();
    user.setAddress("中国杭州");
    user.setAge(16);
    user.setName("姜文");
    this.userRepositoryCrudRepository.save(user);
}
@Test	//修改数据
public void testCrudRepositoryUpdate() {
    User user = new User();
    user.setId(4);
    user.setAddress("中国广州");
    user.setAge(28);
    user.setName("姜文");
    this.userRepositoryCrudRepository.save(user);
}
@Test	//根据id查询
public void testCrudRepositoryFindById() {
    Optional<User> user = this.userRepositoryCrudRepository.findById(4);
    System.out.println(user);
}
@Test	//查询所有
public void testCrudRepositoryFindAll() {
    List<User> userList = (List<User>)this.userRepositoryCrudRepository.findAll();
    for (User user : userList) {
      System.out.println(user);
    }
}
@Test	//根据id删除数据
public void testCrudRepositoryDeleteById() {
  	this.userRepositoryCrudRepository.deleteById(4);
}

六:PagingAndSortingRepository接口

1.该接口提供了分页与排序的操作。该接口集成了CrudRepository接口。

2.编写接口

//PagingAndSortingRepository接口
public interface UserRepositoryPagingAndSorting extends PagingAndSortingRepository<User, Integer> {
}

3.测试代码

//PagingAndSortingRepository--测试
@Test	//排序测试
public void testPagingAndSortingRepositorySort() {
    //Sort对象封装了排序规则
    Sort sort = new Sort(Direction.DESC, "id");
    List<User> userList = (List<User>)this.userRepositoryPagingAndSorting.findAll(sort);
    for (User user : userList) {
      System.out.println(user);
    }
}
@Test	//分页测试
public void testPagingAndSortingRepositoryPaging() {
    //Pageable封装了分页的参数,当前页,每页显示的条数。当前页是从零开始。
    //PageRequest.of(page,size): page当前页,size每页显示的条数
    Pageable pageable = PageRequest.of(0, 2);
    Page<User> page = this.userRepositoryPagingAndSorting.findAll(pageable);
    System.out.println("总条数:"+page.getTotalElements());
    System.out.println("总页数:"+page.getTotalPages());
    for (User user : page.getContent()) {
      System.out.println(user);
    }
}
@Test	//排序+分页排序
public void testPagingAndSortingRepositorySortAndPaging() {
    //PageRequest.of(int page, int size, Direction direction, String... properties)
    //page:当前页,size:每页条数,direction:排序方向,properties:以哪个实体属性进行排序
    Pageable pageable = PageRequest.of(0, 2, Direction.DESC, "id");
    Page<User> page = this.userRepositoryPagingAndSorting.findAll(pageable);
    System.out.println("总条数:"+page.getTotalElements());
    System.out.println("总页数:"+page.getTotalPages());
    for (User user : page.getContent()) {
      System.out.println(user);
    }
}

七:JpaRepository接口

1.该接口继承了PagingAndSortingRepository接口。对继承的父接口中的方法的返回值进行适配。

2.编写接口

//参数一T:当前需要映射的实体
//参数二ID:当前映射的实体中的OID(主键)的类型
public interface UserRepository extends JpaRepository<User, Integer> {
}

3.测试代码

八:JpaSpecificationExecutor接口

1.该接口主要是提供了多条件查询的支持,并且可以在查询中添加分页与排序。JpaSpecificationExecutor是单独存在。完全独立。

2.编写接口

//JpaSpecificationExecutor接口
public interface UserRepositorySpecification extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
}

3.测试代码

//6.JpaSpecificationExecutor--测试
@Test	//单条件测试
public void testJpaSpecificationExecutor1() {
    //Specification:用于封装查询条件, 接口的对象用匿名内部类。
    Specification<User> spec = new Specification<User>() {
        //Predicate:封装了单个的查询条件
        //Root<User> root:查询对象的属性的封装
        //CriteriaQuery<?> query:封装了我们要执行查询中的各个部分信息,select  from  order by
        //CriteriaBuilder criteriaBuilder:查询条件的构造器,定义不同的查询条件
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
            //where name = "周星驰"
            //equal(arg0,arg1): arg0:查询的条件属性  arg1:条件的值
            Predicate pre = criteriaBuilder.equal(root.get("name"), "周星驰");
            return pre;
        }
    };
    List<User> userList = this.userRepositorySpecification.findAll(spec);
    for (User user : userList) {
      	System.out.println(userList);
    }
}
@Test	//多条件测试
public void testJpaSpecificationExecutor2() {
    Specification<User> spec = new Specification<User>() {
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
            //一个Predicate封装一个查询条件,两个条件用数组或集合
            Predicate[] pre = new Predicate[] {
              criteriaBuilder.equal(root.get("name"), "周星驰"),
              criteriaBuilder.equal(root.get("age"), 36)
            };
            //and(pre):pre是可变数组,通过and方法将多个条件连接起来
            return criteriaBuilder.and(pre);
          }
    };
    List<User> userList = this.userRepositorySpecification.findAll(spec);
    for (User user : userList) {
      	System.out.println(user);
    }
}

4.多条件查询的第二种写法

@Test	//多条件测试第二种写法
public void testJpaSpecificationExecutor3() {
    Specification<User> spec = new Specification<User>() {
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
          //一个Predicate封装一个查询条件,两个条件用数组或集合
          //and(pre):pre是可变数组,通过and方法将多个条件连接起来
          //return criteriaBuilder.and(criteriaBuilder.equal(root.get("name"), "周星驰"),criteriaBuilder.equal(root.get("age"), 36));
          //where (name = "周星驰" and age = 36) or id = 1	 --and的优先级比or高,不用括号也可以
          return criteriaBuilder.or(criteriaBuilder.and(criteriaBuilder.equal(root.get("name"), "周星驰"),criteriaBuilder.equal(root.get("age"), 36)),criteriaBuilder.equal(root.get("id"), "1"));
        }
    };
    //sort封装排序规则
    Sort sort = new Sort(Direction.DESC, "id");
    List<User> userList = this.userRepositorySpecification.findAll(spec,sort);
    for (User user : userList) {
     	 System.out.println(user);
    }
}

九:关联映射操作

1.一对多的关联关系

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

角色:一方(Role)	用户:多方(User)

1.1 User实体类

//多对一关系
@ManyToOne(cascade=CascadeType.PERSIST)		//级联添加(添加用户的同时添加相应的角色)
@JoinColumn(name="role_id")	//维护外键
private Role role;	//tostring()方法中不能打印输出role对象,编译会报错

1.2 Role实体类

//一对多关系
@OneToMany(mappedBy="role")		//添加user中外键对象属性
private Set<User> users = new HashSet<>();

1.3测试多对一的关联关系

//多对一关系测试
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=Application.class)
public class OneToManyTest {	
	@Autowired
	private UserRepository userRepository;
	//多对一关系的添加
	@Test
	public void testSave() {
		//创建一个用户
		User user = new User();
		user.setAddress("中国杭州");
		user.setAge(32);
		user.setName("姜文");
		//创建一个角色
		Role role = new Role();
		role.setRolename("管理员");
		//关联
		role.getUsers().add(user);	//主表(先添加主表数据)
		user.setRole(role);			//从表(再添加从表数据)
		//保存
		this.userRepository.save(user);
	}	
	//多对一关系的查询
	@Test
	public void testFind() {
		Optional<User> user = this.userRepository.findById(5);	//根据id查询User
		System.out.println(user.get());	//打印输出User对象
		String rolename = user.get().getRole().getRolename();	//获取rolename
		System.out.println(rolename);
	}
}

2.多对多的关联关系

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

角色:多方	菜单:多方

2.1 Role实体类

//@JoinTable:映射中间表
//中间表中属性joinColumns:当前表主键所关联的中间表中的外键字段
//CascadeType.PERSIST添加数据时级联新建,FetchType.EAGER表示关系类在主体类加载的时候同时加载,立即加载
@ManyToMany(cascade=CascadeType.PERSIST,fetch=FetchType.EAGER)
@JoinTable(name="t_role_menu",joinColumns=@JoinColumn(name="role_id"),inverseJoinColumns=@JoinColumn(name="menu_id"))
private Set<Menu> menus = new HashSet<>();

2.2 Menu实体类

@ManyToMany(mappedBy="menus")	//mappedBy:建立类之间的双向关联,保证数据一致性
private Set<Role> roles = new HashSet<>();

2.3测试多对多的关联关系

//RoleRepository接口
public interface RoleRepository extends JpaRepository<Role, Integer>{
}

//多对多关联关系的测试
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=Application.class)
public class ManyToManyTest {
	@Autowired
	private RoleRepository roleRepository;
	//多对多关系的添加操作
	@Test
	public void testSave() {
		//创建角色对象
		Role role = new Role();
		role.setRolename("项目经理");
		//创建菜单对象
		Menu menu = new Menu();
		menu.setFatherid(0);
		menu.setMenuname("xxx管理系统");
		Menu menu2 = new Menu();
		menu2.setFatherid(1);
		menu2.setMenuname("项目管理");
		//关联
		role.getMenus().add(menu);
		role.getMenus().add(menu2);
		menu.getRoles().add(role);
		menu2.getRoles().add(role);
		//保存
		this.roleRepository.save(role);
	}	
	//多对多关系的查询操作
	@Test
	public void testFind() {
		Optional<Role> role = this.roleRepository.findById(2);
		System.out.println(role.get());
	}
}

十:扩展知识

Java Persistence API定义了一种定义,可以将常规的普通Java对象(有时被称作POJO)映射到数据库。这些普通Java对象被称作Entity Bean。除了是用Java Persistence元数据将其映射到数据库外,Entity Bean与其他Java类没有任何区别。事实上,创建一个Entity Bean对象相当于新建一条记录,删除一个Entity Bean会同时从数据库中删除对应记录,修改一个Entity Bean时,容器会自动将Entity Bean的状态和数据库同步。

@Entity注释指名这是一个实体Bean,@Table注释指定了Entity所要映射带数据库表,其中@Table.name()用来指定映射表的表名。如果缺省@Table注释,系统默认采用类名作为映射表的表名。实体Bean的每个实例代表数据表中的一行数据,行中的一列对应实例中的一个属性。

@Column注释定义了将成员属性映射到关系表中的哪一列和该列的结构信息,属性如下:

1)name:映射的列名。如:映射tbl_user表的name列,可以在name属性的上面或getName方法上面加入;
2)unique:是否唯一;
3)nullable:是否允许为空;
4)length:对于字符型列,length属性指定列的最大字符长度;
5)insertable:是否允许插入;
6)updatetable:是否允许更新;
7)columnDefinition:定义建表时创建此列的DDL;
8)secondaryTable:从表名。如果此列不建在主表上(默认是主表),该属性定义该列所在从表的名字。

@Id注释指定表的主键,它可以有多种生成方式:

1)TABLE:容器指定用底层的数据表确保唯一;
2)SEQUENCE:使用数据库德SEQUENCE列莱保证唯一(Oracle数据库通过序列来生成唯一ID);
3)IDENTITY:使用数据库的IDENTITY列莱保证唯一;
4)AUTO:由容器挑选一个合适的方式来保证唯一;
5)NONE:容器不负责主键的生成,由程序来完成。

@GeneratedValue注释定义了标识字段生成方式。

@Temporal注释用来指定java.util.Date或java.util.Calender属性与数据库类型date、time或timestamp中的那一种类型进行映射。

@OneToOne注释指明User与Card为一对一关系,@OneToOne注释有5个属性:targetEntity、cascade、fetch、optional和mappedBy。

1)targetEntity:Class类型的属性
2)mappedBy:String类型的属性。定义类之间的双向关联。如果类之间是单向关系,不需要提供定义,如果类和类之间形成双向关系。就需要使用这个属性进行定义,否则可能引起数据一致性的问题。
3)cascade:CascadeType类型。该属性定义类和类之间的级联关系。定义级联关系将被容器视为当前类对象及其关联类对象采取相同的操作,而且这种关系是递归的。cascade的值只能从CascadeType.PERSIST(级联新建)、CascadeType.REMOVE(级联删除)、CascadeType.REFRESH(级联刷新)、Cascade.MERGE(级联更新)中选择一个或多个。还有一个选择是使用CascadeType.ALL,表示选择全部四项。
4)fetch:FetchType类型的属性。可选择项包括:FetchType.EAGER和FetchType.LAZY。前者表示关系类在主体类加载的时候同时加载,后者表示关系类在被访问时才加载。默认值是FetchType.LAZY。
5)optional:表示被维护对象是否需要存在。如果为真,说明card属性可以null,也就是允许没有身份证,未成年人就是没有身份证。

实例:

//一对一
//Class Card
@OneToOne(optional=false,cascade=CascadeType.REFRESH)
@JoinColumn(referencedColumnName="id")
private User user;

//一对多
//Class Order
@OneToMany(targetEntity=OrderItem.class,cascade=CascadeType.ALL,mappedBy="order")
private Set set=new HashSet();
//class OrderItem
@ManyToOne(cascade=CascadeType.REFRESH,optional=false)
@JoinColumn(name="item_order_id",referencedColumnName="order_id")
private Order order;

//多对多
//Class Student
@ManyToMany(cascade=CascadeType.ALL,targetEntity=Teacher.class)
@JoinTable(name="tbl_stu_teacher",inverseJoinColumns={@JoinColumn(name="teacher_id",referencedColumnName="teacher_id")},joinColumns={@JoinColumn(name="student_id",referencedColumnName="student_id")})
private Set set=new HashSet();
//Class Teacher
@ManyToMany(targetEntity=Student.class,mappedBy="set")
private Set set=new HashSet();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/367411.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GEE学习笔记 五十二:Google Earth Studio初体验

Google Earth Studio出来一段时间了&#xff0c;自己也体验了一番。这里做一个简单的体验总结&#xff0c;为那些还没有体验过的小伙伴展示一下Google Earth Sutdio究竟长什么样子&#xff0c;能做什么&#xff1f; 注&#xff1a;这篇文章营养价值不大&#xff0c;纯粹是展示…

京东测开岗3+1面经+经验分享,拿到offer,月薪34k....

现在&#xff0c;招聘黄金时间已经来临&#xff0c;在网上看了很多大佬的面经&#xff0c;也加了很多交流群&#xff0c;受到了很多朋友的提点&#xff0c;今天终于轮到我来分享面经啦&#xff0c;之前面试了几家公司&#xff0c;最后拿到了京东测试岗的 offer&#xff0c;这里…

【机器学习、深度学习】损失函数

1.什么是损失函数 ​ 损失函数&#xff08;Loss Function&#xff09;又叫做误差函数&#xff0c;用来衡量算法拟合数据的好坏程度&#xff0c;评价模型的预测值与真实值的不一致程度&#xff0c;是一个非负实值函数&#xff0c;通常使用L(Y, f(x))​来表示&#xff0…

canvas初学1

前端数据可视化方案&#xff1a; 一、canvas绘制直线 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewpor…

CentOS 8利用Apache安装部署文件服务器

1&#xff1a;部署的目的是做一个类似下面开源镜像网站&#xff0c;把一些软件或者资料上传到服务器上面&#xff0c;减少用户在互联网上下载资料&#xff0c;提高效率&#xff0c;减少病毒。 2&#xff1a;使用下面的命令配置本机的IP地址主机名等信息。后期使用IP地址进行访问…

任意网络环境实现外网访问分销ERP

随着企业业务的不断扩展&#xff0c;经营网点遍布全国不同的区域&#xff0c;传统的管理手段存在诸多问题&#xff0c;无法实时监控各地分公司、办事处及营业网点的经营状况&#xff1b;订货、销售、库存等数据和信息反馈不及时&#xff0c;商品积压、缺货情况经常出现&#xf…

软件项目管理知识回顾---软件项目进度管理

软件项目进度管理 4.进度管理 4.1进度管理 1.概念&#xff1a;按时保质的完成任务 2.目的&#xff1a;按时完成任务&#xff0c;合理分配资源&#xff0c;发挥最佳的工作效率 3.活动&#xff1a;工作包分解出的进度活动 4.内容&#xff1a;项目进度计划的指定和项目进度计划的执…

一篇了解分布式id生成方案

系统唯一ID是我们在设计一个系统的时候常常会遇见的问题&#xff0c;也常常为这个问题而纠结。生成ID的方法有很多&#xff0c;适应不同的场景、需求以及性能要求。所以有些比较复杂的系统会有多个ID生成的策略。下面就介绍一些常见的ID生成策略。 1.数据库自增长序列或字段 …

BabylonJS之放烟花

BabylonJS烟花效果视频一&#xff1a; 技术调研 1. 方案一&#xff1a;ParticleSystem 用ParticleSystem来实现每一束的烟花效果&#xff0c;如果浏览器支持WebGL2功能&#xff0c;使用GPUParticleSystem性能会有极大的提升。 优点&#xff1a; 烟花效果易实现且效果好。 缺点…

什么是品牌营销?学会正确推广您的业务

什么是品牌营销&#xff1f; 品牌营销涉及长期战略规划&#xff0c;以推广整个品牌&#xff0c;而不是营销单个产品或服务。它分享了一个引人入胜的故事&#xff0c;以在潜在客户中产生品牌知名度并建立声誉。 面向消费者的品牌使用品牌智能软件来了解人们对其品牌的看法&#…

磨金石教育摄影技能干货分享|极简艺术与人文摄影相结合(一)

柏林街头&#xff08;德国&#xff09;照片中无论是景物元素还是色彩元素都很少&#xff0c;主体人物与道路外加一个箱子。极简艺术照片的减法做到了。一名女子端坐在路边&#xff0c;白色的衣服一尘不染&#xff0c;手持镜子补妆。虽然时间场地比较的随意&#xff0c;但是依然…

R统计绘图 | 物种组成冲积图(绝对/相对丰度,ggalluvial)

一、数据准备 数据使用的不同处理土壤样品的微生物组成数据&#xff0c;包含物种丰度&#xff0c;分类单元和样本分组数据。此数据为虚构&#xff0c;可用于练习&#xff0c;请不要作他用。 # 1.1 设置工作路径 #knitr::opts_knit$set(root.dir"D:\\EnvStat\\PCA")#…

A/B 测试成为企业“新窗口”:增长盈利告别经验主义,数据科学才是未来

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 如何能够预知一个产品的未来&#xff1f;最好的办法当然是穿越到未来看一看。 这种“模拟未来、窥探底牌”的设想似乎只是一种天方夜谭。尤其在数字化浪潮冲击下&a…

磨金石教育摄影技能干货分享|杨元惺佳作欣赏——诗意人文

一般来说&#xff0c;人文摄影总会体现现实性多些。但杨老师是个摄影诗人&#xff0c;他的内心总能将刻板的现实融入美好的光芒。你在他的照片里&#xff0c;看着现实的摄影素材&#xff0c;所感受到的是诗意的绵绵未尽。春网&#xff08;中国&#xff09;正所谓春水碧于天&…

Word控件Spire.Doc 【Table】教程(19):在 C# 中的 Word 中添加/获取表格的替代文本

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

7、STM32 FSMC驱动SRAM

本次使用CubeMx配置FSMC驱动SRAM,XM8A51216 IS62WV51216 原理图&#xff1a; 注意&#xff1a;FSMC_A0必须对应外部设备A0引脚 一、FSMC和FMC区别 FSMC&#xff1a;灵活的静态存储控制器 FMC:灵活存储控制器 区别&#xff1a;FSMC只能驱动静态存储控制器&#xff08;如&…

软考中级有用吗

当然有用了&#xff01; 软考“简历”&#xff1a;计算机软件资格考试在全国范围内已经实施了二十多年&#xff0c;近十年来,考试规模持续增长&#xff0c;截止目前,累计报考人数约有五百万人。该考试由于其权威性和严肃性&#xff0c;得到了社会各界及用人单位的广泛认同&…

哈希函数的学习算法整理

前言 如果你对这篇文章可感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 概述 哈希函数学习的两个步骤&#xff1a; 转为二进制编码&#xff1a;可以先降维成实数&#xff0c;再转为二进制&…

【Spark分布式内存计算框架——离线综合实战】4. IP 工具类

2.2 IP 工具类 需要将IP地址代码封装到工具类中&#xff0c;方便后续使用&#xff0c;在包【cn.itcast.spark.utils】创建工具类&#xff1a;IpUtils.scala&#xff0c;定义方法【convertIpToRegion】&#xff0c;传递参数【ip地址和DbSearch对象】&#xff0c;返回Region对象…

数据结构-树的理解

目录 一&#xff1a;要解决的问题&#xff0c;出发点 1.演进 树的定义&#xff1a; 树的深度&#xff08;高度&#xff09; 平衡二叉树&#xff08;AVL树&#xff09; 红黑树&#xff1a; B树&#xff1a; 深夜有感&#xff0c;灵感乍现&#xff0c;忽然感觉对这个数据结…