11 | JpaRepository 如何自定义

EntityManager 介绍

Java Persistence API 规定,操作数据库实体必须要通过 EntityManager 进行,而我们前面看到了所有的 Repository 在 JPA 里面的实现类是 SimpleJpaRepository,它在真正操作实体的时候都是调用 EntityManager 里面的方法。

我们在 SimpleJpaRepository 里面设置一个断点,这样可以很容易看得出来 EntityManger 是 JPA 的接口协议,而其现类是 Hibernate 里面的 SessionImpl,如下图所示:

Drawing 0.png

那么我们看看 EntityManager 给我们提供了哪些方法。

EntityManager 方法有哪些?

下面介绍几个重要的、比较常用的方法,不常用的我将一笔带过,如果你有兴趣可以自行查看。

复制代码

public interface EntityManager {//用于将新创建的Entity纳入EntityManager的管理。该方法执行后,传入persist()方法的 Entity 对象转换成持久化状态。public void persist(Object entity);//将游离态的实体merge到当前的persistence context里面,一般用于更新。public <T> T merge(T entity);//将实体对象删除,物理删除public void remove(Object entity);//将当前的persistence context中的实体,同步到数据库里面,只有执行了这个方法,上面的EntityManager的操作才会DB生效;public void flush();//根据实体类型和主键查询一个实体对象;public <T> T find(Class<T> entityClass, Object primaryKey);//根据JPQL创建一个Query对象public Query createQuery(String qlString);//利用CriteriaUpdate创建更新查询public Query createQuery(CriteriaUpdate updateQuery);//利用原生的sql语句创建查询,可以是查询、更新、删除等sqlpublic Query createNativeQuery(String sqlString);...//其他方法我就不一一列举了,用法很简单,我们只要参看SimpleJpaRepository里面怎么用的,我们怎么用就可以了;
}

这一课时我们先知道 EntityManager 的语法和用法就好,在之后的第 21 课时介绍 Persistence Context 的时候,再详细讲一下其对实体状态的影响,以及每种状态代表什么意思。

那么现在你知道了这些语法,该怎么使用呢?

EntityManager 如何使用?

它的使用方法很简单,我们在任何地方只要能获得 EntityManager,就可以进行里面的操作。

获得 EntityManager 的方式:通过 @PersistenceContext 注解。

将 @PersistenceContext 注解标注在 EntityManager 类型的字段上,这样得到的 EntityManager 就是容器管理的 EntityManager。由于是容器管理的,所以我们不需要、也不应该显式关闭注入的 EntityManager 实例。

下面是关于这种方式的例子,我们想要在测试类中获得 @PersistenceContext 里面的 EntityManager,看看代码应该怎么写。

复制代码

@DataJpaTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class UserRepositoryTest {//利用该方式获得entityManager@PersistenceContextprivate EntityManager entityManager;@Autowiredprivate UserRepository userRepository;/*** 测试entityManager用法** @throws JsonProcessingException*/@Test@Rollback(false)public void testEntityManager() throws JsonProcessingException {//测试找到一个User对象User user = entityManager.find(User.class,2L);Assertions.assertEquals(user.getAddresses(),"shanghai");//我们改变一下user的删除状态user.setDeleted(true);//merger方法entityManager.merge(user);//更新到数据库里面entityManager.flush();//再通过createQuery创建一个JPQL,进行查询List<User> users =  entityManager.createQuery("select u From User u where u.name=?1").setParameter(1,"jack").getResultList();Assertions.assertTrue(users.get(0).getDeleted());}
}

我们通过这个测试用例,可以知道 EntityManager 使用起来还是比较容易的。不过在实际工作中,我不建议直接操作 EntityManager,因为如果你操作不熟练的话,会出现一些事务异常。因此我还是建议你通过 Spring Data JPA 给我们提供的 Repositories 方式进行操作。
提示一下,你在写框架的时候可以直接操作 EntityManager,切记不要在任何业务代码里面都用到 EntityManager,否则自己的代码到最后就会很难维护

EntityManager 我们了解完了,那么我们再看下 @EnableJpaRepositories 对自定义 Repository 起了什么作用。

@EnableJpaRepositories 详解

下面分别从 @EnableJpaRepositories 的语法,以及其默认加载方式来详细介绍一下。

@EnableJpaRepositories 语法

我们还是直接看代码,如下所示:

复制代码

public @interface EnableJpaRepositories {String[] value() default {};String[] basePackages() default {};Class<?>[] basePackageClasses() default {};Filter[] includeFilters() default {};Filter[] excludeFilters() default {};String repositoryImplementationPostfix() default "Impl";String namedQueriesLocation() default "";Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;Class<?> repositoryFactoryBeanClass() default JpaRepositoryFactoryBean.class;Class<?> repositoryBaseClass() default DefaultRepositoryBaseClass.class;String entityManagerFactoryRef() default "entityManagerFactory";String transactionManagerRef() default "transactionManager";boolean considerNestedRepositories() default false;boolean enableDefaultTransactions() default true;
}

下面我对里面的 10 个方法进行一下具体说明:

1)value 等于 basePackage

用于配置扫描 Repositories 所在的 package 及子 package。

可以配置为单个字符串。

复制代码

@EnableJpaRepositories(basePackages = "com.example")

也可以配置为字符串数组形式,即多个情况。

复制代码

@EnableJpaRepositories(basePackages = {"com.sample.repository1", 	"com.sample.repository2"})

默认 @SpringBootApplication 注解出现目录及其子目录。

2)basePackageClasses

指定 Repository 类所在包,可以替换 basePackage 的使用。

一样可以单个字符,下面例子表示 BookRepository.class 所在 Package 下面的所有 Repositories 都会被扫描注册。

复制代码

@EnableJpaRepositories(basePackageClasses = BookRepository.class)

也可以多个字符,下面的例子代表 ShopRepository.class, OrganizationRepository.class 所在的 package下面的所有 Repositories 都会被扫描。

复制代码

@EnableJpaRepositories(basePackageClasses = {ShopRepository.class, OrganizationRepository.class})

3)includeFilters

指定包含的过滤器,该过滤器采用 ComponentScan 的过滤器,可以指定过滤器类型。

下面的例子表示只扫描带 Repository 注解的类。

复制代码

@EnableJpaRepositories( includeFilters={@ComponentScan.Filter(type=FilterType.ANNOTATION, value=Repository.class)})

4)excludeFilters

指定不包含过滤器,该过滤器也是采用 ComponentScan 的过滤器里面的类。

下面的例子表示,带 @Service 和 @Controller 注解的类,不用扫描进去,当我们的项目变大了之后可以加快应用的启动速度。

复制代码

@EnableJpaRepositories(excludeFilters={@ComponentScan.Filter(type=FilterType.ANNOTATION, value=Service.class),@ComponentScan.Filter(type=FilterType.ANNOTATION, value=Controller.class)})

5)repositoryImplementationPostfix

当我们自定义 Repository 的时候,约定的接口 Repository 的实现类的后缀是什么,默认是 Impl。例子我在下面详细讲解。

6)namedQueriesLocation

named SQL 存放的位置,默认为 META-INF/jpa-named-queries.properties

例子如下:

复制代码

Todo.findBySearchTermNamedFile=SELECT t FROM Table t WHERE LOWER(t.description) LIKE LOWER(CONCAT('%', :searchTerm, '%')) ORDER BY t.title ASC

这个你知道就行了,我建议不要用,因为它虽然功能很强大,但是,当我们使用了这么复杂的方法时,你需要想一想是否有更简单的方法。

7)queryLookupStrategy

构建条件查询的查找策略,包含三种方式:CREATE、USE_DECLARED_QUERY、CREATE_IF_NOT_FOUND。

正如我们前几课时介绍的:

  • CREATE:按照接口名称自动构建查询方法,即我们前面说的 Defining Query Methods;
  • USE_DECLARED_QUERY:用 @Query 这种方式查询;
  • CREATE_IF_NOT_FOUND:如果有 @Query 注解,先以这个为准;如果不起作用,再用 Defining Query Methods;这个是默认的,基本不需要修改,我们知道就行了。

8)repositoryFactoryBeanClass

指定生产 Repository 的工厂类,默认 JpaRepositoryFactoryBean。JpaRepositoryFactoryBean 的主要作用是以动态代理的方式,帮我们所有 Repository 的接口生成实现类。例如当我们通过断点,看到 UserRepository 的实现类是 SimpleJpaRepository 代理对象的时候,就是这个工厂类干的,一般我们很少会去改变这个生成代理的机制。

9)entityManagerFactoryRef

用来指定创建和生产 EntityManager 的工厂类是哪个,默认是 name=“entityManagerFactory” 的 Bean。一般用于多数据配置。

10)Class repositoryBaseClass()

用来指定我们自定义的 Repository 的实现类是什么。默认是 DefaultRepositoryBaseClass,即表示没有指定的 Repository 的实现基类。

11)String transactionManagerRef() default “transactionManager”

用来指定默认的事务处理是哪个类,默认是 transactionManager,一般用于多数据源。

以上就是 @EnableJpaRepositories 的基本语法了,涉及的方法比较多,你可以慢慢探索。下面再看看默认是怎么加载的。

@EnableJpaRepositories 默认加载方式

默认情况下是 spring boot 的自动加载机制,通过 spring.factories 的文件加载 JpaRepositoriesAutoConfiguration,如下图:

Drawing 1.png

JpaRepositoriesAutoConfiguration 里面再进行 @Import(JpaRepositoriesRegistrar.class) 操作,显示如下:

Drawing 2.png

而 JpaRepositoriesRegistrar.class 里面配置了 @EnableJpaRepositories,从而使默认值产生了如下效果:

Drawing 3.png

这样关于 @EnableJpaRepositories 的语法以及默认加载方式就介绍完了,你就可以知道通过 @EnableJpaRepositories 可以完成很多我们自定义的需求。那么到底如何定义自己的 Repository 的实现类呢?我们接着看。

自定义 Repository 的 impl 的方法

定义自己的 Repository 的实现,有以下两种方法。

第一种方法:定义独立的 Repository 的 Impl 实现类

我们通过一个实例说明一下,假设我们要实现一个逻辑删除的功能,看看应该怎么做?

第一步:定义一个 CustomizedUserRepository 接口。

此接口会自动被 @EnableJpaRepositories 开启之后扫描到,代码如下:

复制代码

package com.example.jpa.example1.customized;
import com.example.jpa.example1.User;
public interface CustomizedUserRepository {User logicallyDelete(User user);
}

第二步:创建一个 CustomizedUserRepositoryImpl 实现类。

并且实现类用我们上面说过的 Impl 结尾,如下所示:

复制代码

package com.example.jpa.example1.customized;
import com.example.jpa.example1.User;
import javax.persistence.EntityManager;
public class CustomizedUserRepositoryImpl implements CustomizedUserRepository {private EntityManager entityManager;public CustomizedUserRepositoryImpl(EntityManager entityManager) {this.entityManager = entityManager;}@Overridepublic User logicallyDelete(User user) {user.setDeleted(true);return entityManager.merge(user);}
}

其中我们也发现了 EntityManager 的第二种注入方式,即直接放在构造方法里面,通过 Spring 自动注入。

第三步:当用到 UserRepository 的时候,直接继承我们自定义的 CustomizedUserRepository 接口即可。

复制代码

public interface UserRepository extends JpaRepository<User,Long>, JpaSpecificationExecutor<User>, CustomizedUserRepository {
}

第四步:写一个测试用例测试一下。

复制代码

@Test
public void testCustomizedUserRepository() {//查出来一个User对象User user = userRepository.findById(2L).get();//调用我们的逻辑删除方法进行删除userRepository.logicallyDelete(user);//我们再重新查出来,看看值变了没有List<User> users = userRepository.findAll();Assertions.assertEquals(users.get(0).getDeleted(),Boolean.TRUE);
}

最后调用刚才我们自定义的逻辑删除方法 logicallyDelete,跑一下测试用例,结果完全通过。那么此种方法的实现原理是什么呢?我们通过 debug 分析一下。

原理分析

我们在上面讲过 Class<?> repositoryFactoryBeanClass() default JpaRepositoryFactoryBean.class,repository 的动态代理创建工厂是: JpaRepositoryFactoryBean,它会帮我们生产 repository 的实现类,那么我们直接看一下JpaRepositoryFactoryBean 的源码,分析其原理。

Drawing 4.png

设置一个断点,就会发现,每个 Repository 都会构建一个 JpaRepositoryFactory,当 JpaRepositoryFactory 加载完之后会执行 afterPropertiesSet() 方法,找到 UserRepository 的 Fragment(即我们自定义的 CustomizedUserRepositoryImpl),如下所示:

Drawing 5.png

我们再看 RepositoryFactory 里面的所有方法,如下图,一看就是动态代理生成 Repository 的实现类,我们进到这个方法里面设置个断点继续观察。

Drawing 6.png

然后我们通过断点可以看到,fragments 放到了 composition 里面,最后又放到了 advice 里面,最后才生成了我们的 repository 的代理类。这时我们再打开 repository 详细地看看里面的值。

Drawing 7.png

可以看到 repository 里面的 interfaces,就是我们刚才测试 userRepository 里面的接口定义的。

Drawing 8.png

我们可以看到 advisors 里面第六个就是我们自定义的接口的实现类,从这里可以得出结论:spring 通过扫描所有 repository 的接口和实现类,并且通过 aop 的切面和动态代理的方式,可以知道我们自定义的接口的实现类是什么。

针对不同的 repository 自定义的接口和实现类,需要我们手动去 extends,这种比较适合不同的业务场景有各自的 repository 的实现情况。还有一种方法是我们直接改变动态代理的实现类,我们接着看。

第二种方法:通过 @EnableJpaRepositories 定义默认的 Repository 的实现类

当面对复杂业务的时候,难免会自定义一些公用的方法,或者覆盖一些默认实现的情况。举个例子:很多时候线上的数据是不允许删除的,所以这个时候需要我们覆盖 SimpleJpaRepository 里面的删除方法,换成更新,进行逻辑删除,而不是物理删除。那么接下来我们看看应该怎么做?

第一步:正如上面我们讲的利用 @EnableJpaRepositories 指定 repositoryBaseClass,代码如下:

复制代码

@SpringBootApplication
@EnableWebMvc
@EnableJpaRepositories(repositoryImplementationPostfix = "Impl",repositoryBaseClass = CustomerBaseRepository.class)
public class JpaApplication {public static void main(String[] args) {SpringApplication.run(JpaApplication.class, args);}
}

可以看出,在启动项目的时候,通过 @EnableJpaRepositories 指定我们 repositoryBaseClass 的基类是 CustomerBaseRepository。

第二步:创建 CustomerBaseRepository 继承 SimpleJpaRepository 即可。

继承 SimpleJpaRepository 之后,我们直接覆盖 delete 方法即可,代码如下:

复制代码

package com.example.jpa.example1.customized;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
@Transactional(readOnly = true)
public class CustomerBaseRepository<T extends BaseEntity,ID> extends SimpleJpaRepository<T,ID>  {private final JpaEntityInformation<T, ?> entityInformation;private final EntityManager em;public CustomerBaseRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {super(entityInformation, entityManager);this.entityInformation = entityInformation;this.em = entityManager;}public CustomerBaseRepository(Class<T> domainClass, EntityManager em) {super(domainClass, em);entityInformation = null;this.em = em;}//覆盖删除方法,实现逻辑删除,换成更新方法@Transactional@Overridepublic void delete(T entity) {entity.setDeleted(Boolean.TRUE);em.merge(entity);}
}

需要注意的是,这里需要覆盖父类的构造方法,接收 EntityManager,并赋值给自己类里面的私有变量。

第三步:写一个测试用例测试一下。

复制代码

@Test
public void testCustomizedBaseRepository() {User user = userRepository.findById(2L).get();userRepository.logicallyDelete(user);userRepository.delete(user);List<User> users = userRepository.findAll();Assertions.assertEquals(users.get(0).getDeleted(),Boolean.TRUE);
}

你可以发现,我们执行完“删除”之后,数据库里面的 User 还在,只不过 deleted,变成了已删除状态。那么这是为什么呢?我们分析一下原理。

原理分析

还是打开 RepositoryFactory 里面的父类方法,它会根据 @EnableJpaRepositories 里面我们配置的 repositoryBaseClass,加载我们自定义的实现类,关键方法如下:

Drawing 9.png

我们还看刚才的方法的断点,如下:

Drawing 10.png

可以看到 information 已经变成了我们扩展的基类了,而最终生成的 repository 的实现类也换成了 CustomerBaseRepository。

自定义的方法,我们讲完了,那么它都会在哪些实际场景用到呢?接着看一下。

实际应用场景是什么?

在实际工作中,有哪些场景会用到自定义 Repository 呢?

  1. 首先肯定是我们做框架的时候、解决一些通用问题的时候,如逻辑删除,正如我们上面的实例所示的样子。
  2. 在实际生产中经常会有这样的场景:对外暴露的是 UUID 查询方法,而对内暴露的是 Long 类型的 ID,这时候我们就可以自定义一个 FindByIdOrUUID 的底层实现方法,可以选择在自定义的 Respository 接口里面实现。
  3. Defining Query Methods 和 @Query 满足不了我们的查询,但是我们又想用它的方法语义的时候,就可以考虑实现不同的 Respository 的实现类,来满足我们不同业务场景的复杂查询。我见过有团队这样用过,不过个人感觉一般用不到,如果你用到了说明你的代码肯定有优化空间,代码不应该过于复杂。

上面我们讲到了逻辑删除,还有一个是利用 @SQLDelete 也可以做到,用法如下:

复制代码

@SQLDelete(sql = "UPDATE user SET deleted = true where deleted =false and id = ?")
public class User implements Serializable {
....
}

这个时候不需要我们自定义 Respository 也可做到,这个方法的优点就是灵活,而缺点就是需要我们一个一个配置在实体上面。你可以根据实际场景自由选择方式。

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

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

相关文章

云上攻防-云原生篇K8s安全Config泄漏Etcd存储Dashboard鉴权Proxy暴露

文章目录 云原生-K8s安全-etcd未授权访问云原生-K8s安全-Dashboard未授权访问云原生-K8s安全-Configfile鉴权文件泄漏云原生-K8s安全-Kubectl Proxy不安全配置 云原生-K8s安全-etcd未授权访问 攻击2379端口&#xff1a;默认通过证书认证&#xff0c;主要存放节点的数据&#x…

升级包版本之后Reflections反射包在springboot jar环境下扫描不到class排查过程记录

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是「奇点」&#xff0c;江湖人称 singularity。刚工作几年&#xff0c;想和大家一同进步&#x1f91d;&#x1f91d; 一位上进心十足的【Java ToB端大厂…

卡顿分析与布局优化

卡顿分析与布局优化 大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。Android系统每隔大概16.6ms发出VSYNC信 号&#xff0c;触发对UI进行渲染&#xff0c;如果每次渲染都成功&#xff0c;这样就能够达到流畅的画面所需要的60fps&#xff0c;为了能够实现60fp…

LabVIEW生产者消费者架构

LabVIEW生产者消费者架构 生产者/消费者模式可以轻松地同时处理多个进程&#xff0c;同时还能以不同速率迭代。 缓冲通信 当多个进程以不同速度运行时&#xff0c;就适合采用进程间缓冲通信。有了足够大的缓冲区后&#xff0c;生产者循环可以以快于消费者循环的速度运行&…

c语言练习89:链表的使用

链表的使用 虽然有这么多的链表的结构&#xff0c;但是我们实际中最常⽤还是两种结构&#xff1a; 单链表 和 双向带头循环链表 1. ⽆头单向⾮循环链表&#xff1a;结构简单&#xff0c;⼀般不会单独⽤来存数据。实际中更多是作为其他数据结 构的⼦结构&#xff0c;如哈希桶、…

在vs code中创建一个名为 “django_env“ 的虚拟环境报错?!以下方法可以解决

# vs code 终端窗口中运行&#xff1a; mkvirtualenv django_env # 拓展&#xff1a; mkvirtualenv django_env 是一个命令&#xff0c;用于创建一个名为 "django_env" 的虚拟环境。虚拟环境是一种用于隔离不同Python项目所需依赖的工具。通过创建虚拟环境&#x…

word 如何编写4x4矩阵

百度上给的教程&#xff0c;打印出来没有对齐 https://jingyan.baidu.com/article/6b182309995f8dba58e159fc.html 百度上的方式试了一下&#xff0c;不会对齐。导致公式看起来很奇怪。 下面方式会自动对齐 摸索了一下发现可以用下面这种方式编写 4x4 矩阵。先创建一个 3x3…

基于Linux上MySQL8.*版本的安装-参考官网

本地hadoop环境安装好,并安装好mysql mysql下载地址及选择包 MySQL :: Download MyS的QL Community Server (Archived Versions) mysql安装步骤 下载与上传解压给权限 #mysql安装包上传到/opt下 cd /usr/local/ #解压到此目录 tar -xvf /opt/mysql-8.0.33-linux-glibc2.12-…

[Machine Learning][Part 5]监督学习——逻辑回归

之前文章中提到监督学习的应用可分为两类&#xff1a;线性回归和逻辑回归。和线性回归不同&#xff0c;逻辑回归输出只有0和1。对于一个逻辑回归任务&#xff0c;可以先使用线性回归来预测y。然而我们希望逻辑回归预测模型输出的是0和1&#xff0c;为了达到这个目的&#xff0c…

Ubuntu:VS Code IDE安装ESP-IDF【保姆级】

物联网开发学习笔记——目录索引 参考&#xff1a; VS Code官网&#xff1a;Visual Studio Code - Code Editing. Redefined 乐鑫官网&#xff1a;ESP-IDF 编程指南 - ESP32 VSCode ESP-ID Extension Install 一、前提条件 Visual Studio Code IDE安装ESP-IDF扩展&…

微信小程序 uniapp+vue线上洗衣店业务管理系统演89iu2

本课题意在设计一种系统的、基于用户体验的线上洗衣服务模式&#xff0c;具有如下的研究意义: (1)为用户提供更简单、便捷的洗衣服务模式; (2)为智能柜的盈利模式提供了新的方向; (3)通过线上系统、智能柜与洗衣工厂结合的方式&#xff0c;为洗衣企业构建了一套节 省人力成本的…

使用VS Code终端窗口创建Python虚拟环境

在日常的Python开发中&#xff0c;管理项目的依赖关系是至关重要的。一个非常有用的工具是Python虚拟环境&#xff0c;它允许我们可以在同一计算机上隔离不同项目的依赖&#xff0c;以确保它们不会相互干扰。在本文中&#xff0c;我们将介绍如何在VS Code终端窗口中使用命令mkv…

论文阅读:CenterFormer: Center-based Transformer for 3D Object Detection

目录 概要 Motivation 整体架构流程 技术细节 Multi-scale Center Proposal Network Multi-scale Center Transformer Decoder Multi-frame CenterFormer 小结 论文地址&#xff1a;[2209.05588] CenterFormer: Center-based Transformer for 3D Object Detection (arx…

WSL Ubuntu 22.04.2 LTS 安装paddle踩坑日记

使用conda安装paddlepaddle-gpu: conda install paddlepaddle-gpu2.5.1 cudatoolkit11.7 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/Paddle/ -c conda-forge 等待安装... 报错处理&#xff1a; (1)(1)PreconditionNotMetError: Cannot load cudnn shared libr…

205、使用消息队列实现 RPC(远程过程调用)模型的 服务器端 和 客户端

目录 ★ RPC模型&#xff08;远程过程调用通信模型&#xff09;▲ 完整过程&#xff1a;代码演示总体流程解释&#xff1a;ConstantUtil 常量工具类ConnectionUtil RabbitMQ连接工具类Server 服务端Client 客户端测试结果服务端客户端 完整代码ConstantUtil 常量工具类Connecti…

AMD AFMF不但能用在游戏,也适用于视频

近期AMD发布了AMD Software Adrenalin Edition预览版驱动程序&#xff0c;增加了对平滑移动帧&#xff08;AMD Fluid Motion Frames&#xff0c;AFMF&#xff09;功能的支持&#xff0c;也就是AMD的“帧生成”技术&#xff0c;与DLSS 3类似&#xff0c;作为FidelityFX Super Re…

137. 只出现一次的数字 II

题目 题解 方法一 直接用 哈希表出现 3 次则从 哈希表移除&#xff0c;最后剩下的就是结果 class Solution { public int singleNumber(int[] nums) { Map<Integer, Integer> map new HashMap<>(); for (int num : nums) { Integer i…

React添加文件路径时使用@符号代替src目录(非creae-react-app)

在其它项目中看到的可以用符号来代替src目录&#xff0c;那么在自己的react项目中也必须得尝试一下。本人的项目不是通过create-react-app脚手架来创建的&#xff0c;无法使用craco或者的方案来实现。 jsconfig.json配置 用的vscode进行开发&#xff0c;查看项目当中是否存在js…

css 如何让元素内部文本和外部文本 一块显示省略号

实际上还是有这样的需求的 <div class"container"><span>啊啊啊啊啊啊啊啊</span>你好啊撒撒啊撒撒撒撒啊撒撒撒撒撒说</div>还是有这样的需求的哦。 div.container {width: 200px;white-space: nowrap;text-overflow: ellipsis;overflow:…

【AI视野·今日Robot 机器人论文速览 第五十期】Mon, 9 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Mon, 9 Oct 2023 Totally 25 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Learning to Grasp: from Somewhere to Anywhere Authors Fran ois H l non, Johann Huber, Fa z Ben Amar, St phane Doncieux…