当前位置: 首页 > news >正文

动态网站开发与全程实例pdf/seo外链建设的方法有

动态网站开发与全程实例pdf,seo外链建设的方法有,wordpress 自定义投稿,武汉app开发外包公司Spring整合Mybaits的步骤 引入依赖 在Spring整合Mybaits的时候需要引入一个中间依赖包mybatis-spring <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version> </dependency&g…

Spring整合Mybaits的步骤

引入依赖

在Spring整合Mybaits的时候需要引入一个中间依赖包mybatis-spring

<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version>
</dependency>
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.2</version>
</dependency>

添加spring配置

为了整合mybatis,需要在spring的配置文件中引入mybtis的配置,这些配置通过两个类实现,SqlSessionFactoryBean以及MapperFactoryBean;SqlSessionFactoryBean负责加载mybatis-config文件以及注入数据源,MapperFactoryBean负责加载mapper接口

<?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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd
"><bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"   destroy-method="close"><property name="driverClassName" value="com.mysql.jdbc.Driver"></property><property name="username" value="root"></property><property name="password" value="husj0423"></property><property name="url" value="jdbc:mysql://localhost:3306/test"></property><property name="initialSize" value="1"></property><property name="maxTotal" value="20"></property><property name="maxIdle" value="5"></property><property name="minIdle" value="2"></property></bean><bean id="userService" class="com.handerh.spring.test.aop.db.jdbc.UserServiceImpl"><property name="dataSource" ref="dataSource"></property></bean><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="configLocation" value="sqlmap/mybatis-config.xml"></property><property name="dataSource" ref="dataSource"></property></bean><bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"><property name="mapperInterface" value="mapper.UserMapper"></property><property name="sqlSessionFactory" ref="sqlSessionFactory"></property></bean></beans>

添加Mybatis配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- mybatis的主配置文件 -->
<configuration>
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
<mappers><mapper resource="sqlmap/UserMapper.xml"/>
</mappers>
</configuration>

测试

public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-mabatis.xml");UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");User user = userMapper.selectByPrimaryKey(6);
}

Spring整合Mybaits源码分析

在Spring与Myabtis整合的配置文件中,配置了两个重要的beanSqlSessionFactoryBean以及MapperFactoryBean,接下来主要分析这两个类是如何将mybatis整合到Spring中

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="configLocation" value="sqlmap/mybatis-config.xml"></property><property name="dataSource" ref="dataSource"></property>
</bean><bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"><property name="mapperInterface" value="mapper.UserMapper"></property><property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>

SqlSessionFactoryBean

在这里插入图片描述

可以看到它实现了两个非常重要的接口:

  • InitializingBean:实现此接口的bean会在初始化时调用afterPropertiesSet方法进行bean的逻辑初始化

  • FactoryBean:一旦某个Bean实现此接口,那么通过getBean获取bean时实际上获取的是此类的getObject返回的实例

SqlSessionFactoryBean的初始化

在实例化SqlSessionFactoryBean会调用afterPropertiesSet方法,在该方法最终会调用buildSqlSessionFactory函数来创建SqlSessionFactory;根据spring配置文件中注入的属性configLocation构造XMLConfigBuilder并且进行解析。Spring不仅可以通过configLocation的方式整合Mybatis的配置,还可以将Mybatis的配置直接整合到Spring配置文件中进行属性注入,并通过targetConfiguration来承载属性,最终使用sqlSessionFactoryBuilder实例根据解析的configuration创建SqlSessionFactory

protected SqlSessionFactory buildSqlSessionFactory() throws Exception {final Configuration targetConfiguration;XMLConfigBuilder xmlConfigBuilder = null;
if (this.configuration != null) {targetConfiguration = this.configuration;if (targetConfiguration.getVariables() == null) {targetConfiguration.setVariables(this.configurationProperties);} else if (this.configurationProperties != null) {targetConfiguration.getVariables().putAll(this.configurationProperties);}
} else if (this.configLocation != null) {xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);targetConfiguration = xmlConfigBuilder.getConfiguration();
} else {targetConfiguration = new Configuration();Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
}Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);// 类别名
if (hasLength(this.typeAliasesPackage)) {scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream().filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface()).filter(clazz -> !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
}if (!isEmpty(this.typeAliases)) {Stream.of(this.typeAliases).forEach(typeAlias -> {targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);LOGGER.debug(() -> "Registered type alias: '" + typeAlias + "'");});
}//Mybatis插件,可以修改Mybatis内部的允许规则
if (!isEmpty(this.plugins)) {Stream.of(this.plugins).forEach(plugin -> {targetConfiguration.addInterceptor(plugin);LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");});
}//定义类型处理器
if (hasLength(this.typeHandlersPackage)) {scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers())).filter(clazz -> ClassUtils.getConstructorIfAvailable(clazz) != null).forEach(targetConfiguration.getTypeHandlerRegistry()::register);
}if (!isEmpty(this.typeHandlers)) {Stream.of(this.typeHandlers).forEach(typeHandler -> {targetConfiguration.getTypeHandlerRegistry().register(typeHandler);LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");});
}if (!isEmpty(this.scriptingLanguageDrivers)) {Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver -> {targetConfiguration.getLanguageRegistry().register(languageDriver);LOGGER.debug(() -> "Registered scripting language driver: '" + languageDriver + "'");});
}
Optional.ofNullable(this.defaultScriptingLanguageDriver).ifPresent(targetConfiguration::setDefaultScriptingLanguage);if (this.databaseIdProvider != null) {// fix #64 set databaseId before parse mapper xmlstry {targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));} catch (SQLException e) {throw new NestedIOException("Failed getting a databaseId", e);}
}Optional.ofNullable(this.cache).ifPresent(targetConfiguration::addCache);if (xmlConfigBuilder != null) {try {xmlConfigBuilder.parse();LOGGER.debug(() -> "Parsed configuration file: '" + this.configLocation + "'");} catch (Exception ex) {throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);} finally {ErrorContext.instance().reset();}
}
// SpringManagedTransactionFactory 事务工厂
targetConfiguration.setEnvironment(new Environment(this.environment,this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,this.dataSource));// mapper文件解析
if (this.mapperLocations != null) {if (this.mapperLocations.length == 0) {LOGGER.warn(() -> "Property 'mapperLocations' was specified but matching resources are not found.");} else {for (Resource mapperLocation : this.mapperLocations) {if (mapperLocation == null) {continue;}try {XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());xmlMapperBuilder.parse();} catch (Exception e) {throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);} finally {ErrorContext.instance().reset();}LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'");}}
} else {LOGGER.debug(() -> "Property 'mapperLocations' was not specified.");
}return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}

获取SqlSessionFactoryBean的实例

当通过getBean方法获取对应SqlSessionFactoryBean实例时,其实获取到的是getObject返回的初始化后的SqlSessionFactory

public SqlSessionFactory getObject() throws Exception {if (this.sqlSessionFactory == null) {afterPropertiesSet();}return this.sqlSessionFactory;
}

MapperFactoryBean

MapperFactoryBean的继承体系如下:
在这里插入图片描述

可以看到MapperFactoryBean也实现了InitializingBean以及FactoryBean接口,同样的在通过getBean初始化bean实例的前也会调用afterPropertiesSet方法

afterPropertiesSet校验

public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {// Let abstract subclasses check their configuration.checkDaoConfig();// Let concrete implementations initialize themselves.try {initDao();}catch (Exception ex) {throw new BeanInitializationException("Initialization of DAO failed", ex);}
}

这里的checkDaoConfig()方法主要时做一个验证,校验mapperInterface这个属性是否有值,同时将mapperInterface放入到Mybatis的MapperRegistry中。

getObject获取mapper实例

afterPropertiesSet方法主要是做了一个校验逻辑,真正获取mapper实例的逻辑在getObject方法中

public T getObject() throws Exception {return getSqlSession().getMapper(this.mapperInterface);
}
public SqlSession getSqlSession() {return this.sqlSessionTemplate;
}

看到这里其实就是通过SqlSession来创建Mapper实例了,但是这个SqlSession不是独立使用时的DefaultSqlSession,而是SqlSessionTemplate,这个SqlSessionTemplate是什么时候注入的呢,看上面的类图发现SqlSessionTemplate继承了qlSessionDaoSupport,这个类中有一个属性SqlSessionTemplate,还包含一个set方法setSqlSessionFactory,这个方法完成了SqlSessionTemplate的创建,如下:

public abstract class SqlSessionDaoSupport extends DaoSupport {private SqlSessionTemplate sqlSessionTemplate;public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);}}
}

而我们在Spring配置文件中刚好配置为MapperFactoryBean注入了SqlSessionFactory,通过SqlSessionFactory创建SqlSessionTemplate从而完成mapper实例的创建

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"><property name="mapperInterface" value="mapper.UserMapper"></property><property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>

SqlSessionTemplate获取mapper实例

public <T> T getMapper(Class<T> type) {return getConfiguration().getMapper(type, this);
}

通过获取Mybatis配置来创建mapper实例,最终调用的是MapperRegistry.getMapper

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);if (mapperProxyFactory == null) {throw new BindingException("Type " + type + " is not known to the MapperRegistry.");} else {try {//动态代理创建mapper对象,这里的sqlSession是sqlSessionTemplatereturn mapperProxyFactory.newInstance(sqlSession);} catch (Exception var5) {throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);}}
}

mapper代理对象的执行

获取到mapper代理对象之后,就可以执行方法调用了。看一下SqlSessionTemplate中的方法:

public <T> T selectOne(String statement) {return this.sqlSessionProxy.selectOne(statement);
}public <T> T selectOne(String statement, Object parameter) {return this.sqlSessionProxy.selectOne(statement, parameter);
}public int insert(String statement, Object parameter) {return this.sqlSessionProxy.insert(statement, parameter);
}public int update(String statement) {return this.sqlSessionProxy.update(statement);
}

发现所有的增删改方法都是通过sqlSessionProxy来实现的,这个对象则是在初始化SqlSessionTemplate时生成的一个代理对象:

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator) {this.sqlSessionFactory = sqlSessionFactory;this.executorType = executorType;this.exceptionTranslator = exceptionTranslator;this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),new Class[] { SqlSession.class }, new SqlSessionInterceptor());
}

对于JDK动态代理生成的对象方法的调用都说在Invocationhandler中完成的,SqlSessionInterceptor实现了Invocationhandler接口:

private class SqlSessionInterceptor implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 1.获取SqlSessionSqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);try {// 2. 执行目标方法Object result = method.invoke(sqlSession, args);if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {sqlSession.commit(true);}return result;} catch (Throwable t) {Throwable unwrapped = unwrapThrowable(t);if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {// release the connection to avoid a deadlock if the translator is no loaded. See issue #22closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);sqlSession = null;Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);if (translated != null) {unwrapped = translated;}}throw unwrapped;} finally {//3.关闭sqlSessionif (sqlSession != null) {closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);}}
}

在SqlSessionInterceptor有一个获取SqlSession的操作,来看一下:

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator) {//获取SqlSessionHolder,如果是同一个事物,Spring会保证在改事物中获取到的SqlSession是同一个SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);//从SqlSession中获取SqlSessionSqlSession session = sessionHolder(executorType, holder);if (session != null) {return session;}//通过SqlSessionFactory创建DefaultSqlSessionLOGGER.debug(() -> "Creating a new SqlSession");session = sessionFactory.openSession(executorType);//如果开启了事物会将该SqlSession注册到SessionHolder中registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);return session;
}

这段代码的主要逻辑就是创建SqlSession来完成mapper的执行,如果加入了Spring的事物管理,则需要保证在同一个事物中获取到的SqlSession是同一个(事物的提交以及回滚),到这里Mybatis与Spring整合的核心逻辑就已经完成了,另外,Spring为了简化Mapper接口的注册,加入了包扫描,减少在Spring配置文件中的mapper配置。

MapperScannerConfigurer

在Spring配置文件加入如下配置,就不需要为每一个Mapper接口再配置MapperFactoryBean了

<bean  id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="mapper"></property>
</bean>

我们来了解一下MapperScannerConfigurer是如何实现的。先看一下它的继承结构:
在这里插入图片描述

发现MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor,InitializingBean两个接口,不过MapperScannerConfigurer的afterPropertiesSet方法中没有去做任何的逻辑处理,主要逻辑都是在postProcessBeanDefinitionRegistry方法中实现的(实现了BeanDefinitionRegistryPostProcessor接口),这个接口在容器启动的时候(AbstractApplicationContext.refresh())会被调用:

invokeBeanFactoryPostProcessors(beanFactory);
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());}

看一下MapperScannerConfigurer中postProcessBeanDefinitionRegistry的处理逻辑:

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);scanner.setAddToConfig(this.addToConfig);scanner.setAnnotationClass(this.annotationClass);scanner.setMarkerInterface(this.markerInterface);scanner.setSqlSessionFactory(this.sqlSessionFactory);scanner.setSqlSessionTemplate(this.sqlSessionTemplate);scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);scanner.setResourceLoader(this.applicationContext);scanner.setBeanNameGenerator(this.nameGenerator);scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);if (StringUtils.hasText(lazyInitialization)) {scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));}scanner.registerFilters();// 对指定路径完成扫描scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));}

doScan扫描

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();for (String basePackage : basePackages) {// 扫描basePackage下的java文件Set<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {// 解析该bean是否包含scope注解 默认为singleScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());// 生成bean名称 默认首字母小写String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {//检测常用注解:Primary LazyAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检测该bean是否已经注册if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);// 如果当前bean需要被代理 则需要进一步处理definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);// bean的注册beanDefinitions.add(definitionHolder);registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;
}

processBeanDefinitions构造MapperFactoryBean类型的bean

关键代码就下面两行,生成一个MapperFactoryBean类型的Bean,其中的mapperInterface属性,通过构造函数时将代理的beanClassName传入,这样通过包扫描就可以生成许多的MapperFactoryBean类型的Bean,简化Mapper接口的注册

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;for (BeanDefinitionHolder holder : beanDefinitions) {definition = (GenericBeanDefinition) holder.getBeanDefinition();String beanClassName = definition.getBeanClassName();// 构造函数时使用Mapper自身的类,因为MapperFactoryBean中的属性mapperInterface通过构造函数传入,以便进行代理definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59// 实际上该Bean类型为MapperFactoryBeandefinition.setBeanClass(this.mapperFactoryBeanClass);}
} 

总结

spring整合mybatis分为两个方面,一个是加载配置以及mapper实例的初始化,这一块主要通过SqlSessionFactoryBean以及MapperFactoryBean来实现,另一方面是执行流程,通过SqlSessionTemplate以及SqlSessionInterceptor实现

  • SqlSessionFactoryBean:实现了InitiallizeBean,初始化时执行afterProperties方法,根据spring配置文件中的dataSource以及configLocations创建SqlSessionFactory
  • MapperFactoryBean:实现了FactoryBean,在获取bean对象时实际上走的是getObject方法,通过sqlSessionTemplate获取mapper实例
  • SqlSessionTemplate:通过实现SqlSessionDaoSupport接口注入SqlSessionFactory对象时,完成SqlSessionTemplate对象的初始化;它在创建mapper对象时还是通过mybatis原生的配置类来完成的。
  • SqlSessionInterceptor:mapper实例在执行增删改时最终会调用到SqlSession的增删改方法,也就是SqlSessionTemplate的一些方法,这些方法都是通过sqlSessionProxy的一个代理对象来完成的,这个代理对象通过SqlSessionInterceptor创建,在执行具体的方法时会走到SqlSessionInterceptor的invoke方法中,这个方法中才会创建真正的SqlSession负责执行增删改方法,同时将SqlSession与事务关联,如果是同一个事物,Spring会保证在改事物中获取到的SqlSession是同一个。

相关文章:

六、mybatis与spring的整合

Spring整合Mybaits的步骤 引入依赖 在Spring整合Mybaits的时候需要引入一个中间依赖包mybatis-spring <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version> </dependency&g…...

JavaWeb--JDBC

JDBC1 JDBC概述1.1 JDBC概念1.2 JDBC本质1.3 JDBC好处2 JDBC快速入门2.1 编写代码步骤2.2 具体操作3 JDBC API详解3.1 DriverManager3.2 Connection3.2.1 获取执行对象3.2.2 事务管理3.3 Statement3.3.1 概述3.3.2 代码实现3.4 ResultSet3.4.1 概述3.4.2 代码实现3.5 案例3.6 P…...

大数据框架之Hadoop:入门(四)Hadoop运行模式

Hadoop运行模式包括&#xff1a;本地模式、伪分布式模式以及完全分布式模式。 Hadoop官方网站&#xff1a;http://hadoop.apache.org/ 4.1本地运行模式 4.1.1官方Grep案例 1.创建在hadoop文件夹下面创建一个input文件夹 [roothdp101 hadoop]# mkdir input2.将Hadoop的xml配…...

《爆肝整理》保姆级系列教程python接口自动化(十一)--发送post【data】(详解

简介  前面登录的是传 json 参数&#xff0c;由于其登录机制的改变没办法演示&#xff0c;然而在工作中有些登录不是传 json 的&#xff0c;如 jenkins 的登录&#xff0c;这里小编就以jenkins 登录为案例&#xff0c;传 data 参数&#xff0c;给各位童鞋详细演练一下。 一、…...

【微服务】Nacos注册中心

&#x1f6a9;本文已收录至专栏&#xff1a;微服务探索之旅 &#x1f44d;希望您能有所收获 &#x1f44d;Nacos和Eureka一样也可以充当服务的注册中心&#xff0c;让我们一起看看有何区别&#xff1f; 点击跳转&#x1f449;【微服务】Eureka注册中心 &#x1f44d;Nacos除了可…...

跟开发打了半个月后,我终于get报bug的正确姿势了

在测试人员提需求的时候&#xff0c;大家经常会看到&#xff0c;测试员和开发一言不合就上BUG。然后开发一下就炸了&#xff0c;屡试不爽&#xff0c;招招致命。 曾经看到有个段子这么写道&#xff1a; 不要对程序员说&#xff0c;你的代码有BUG。他的第一反应是&#xff1a;…...

js万能类型检测Object.prototype.toString.call——定制Object.prototype.toString.call的检测结果

javascript的类型检测 1、typeof typeof操作符可以检测js的基础数据类型&#xff0c;包括number、string、boolean、undefined。因为null在二进制存储的值与object相同&#xff0c;所以typeof检测null会返回object。此为特例 2、instanceof instanceof操作符可以检测某个对…...

激光slam学习笔记2--激光点云数据结构特点可视化查看

背景&#xff1a;不同厂商的激光点云结果存在一定差异&#xff0c;比如有些只有xyz&#xff0c;有些包含其他&#xff0c;如反光率、时间戳、ring等。如何快速判断是个值得学习的点 概要&#xff1a;对于rosbag类型的激光点云&#xff0c;介绍使用rviz快速查看点云结构特点 如…...

SpringBoot笔记【JavaEE】

SpringBoot概念、创建和运行 1.什么是SpringBoot&#xff1f;为什么学习SpringBoot&#xff1f; Spring Boot 就是 Spring 框架的脚⼿架&#xff0c;它就是为了快速开发 Spring 框架⽽诞⽣的。 2.Spring Boot优点 快速集成框架【提供启动添加依赖的功能】内容运行容器【无需…...

目标检测算法之voxelNet与pointpillars对比

算法对比 3D目标检测发展简史 点云目标检测目前发展历经VoxelNet、SECOND、PointPillars、PV-RCNN。 2017年苹果提出voxelnet&#xff0c;是最早的一篇将点云转成voxel体素进行3D目标检测的论文。 然后2018年重庆大学的一个研究生Yan Yan在自动驾驶公司主线科技实习的时候将vo…...

电脑里的连接速度双工模式是什么?怎么设置

双工模式包括全双工、半双工模式。1.半双工1、半双工数据传输允许数据在两个方向上传输&#xff0c;但是&#xff0c;在某一时刻&#xff0c;只允许数据在一个方向上传输&#xff0c;它实际上是一种切换方向的单工通信。所谓半双工就是指一个时间段内只有一个动作发生。早期的对…...

springboot整合单机缓存ehcache

区别于redis的分布式缓存&#xff0c;ehcache是纯java进程内的单机缓存&#xff0c;根据不同的场景可选择使用&#xff0c;以下内容主要为springboot整合ehcache以及注意事项添加pom引用<dependency><groupId>net.sf.ehcache</groupId><artifactId>ehc…...

在阿里干了2年的测试,总结出来的划水经验

测试新人 我的职业生涯开始和大多数测试人一样&#xff0c;开始接触都是纯功能界面测试。那时候在一家电商公司做测试&#xff0c;做了一段时间&#xff0c;熟悉产品的业务流程以及熟练测试工作流程规范之后&#xff0c;效率提高了&#xff0c;工作比较轻松&#xff0c;这样我…...

硬盘分类及挂载硬盘知识补充和介绍

一、硬盘介绍Linux硬盘分IDE硬盘和SCSI硬盘&#xff0c;目前基本上是SCSI硬盘1.对于IDE硬盘&#xff0c;驱动器标识符为"hdx~"&#xff0c;其中"hd"表明分区所在设备的类型&#xff0c;这里是指IDE硬盘了。"x"为盘号(a为基本盘&#xff0c;b为基…...

【MyBatis】自定义映射resultMap

8.1、resultMap处理字段和属性的映射关系 若字段名和实体类中的属性名不一致&#xff0c;则可以通过resultMap设置自定义映射 <!--resultMap&#xff1a;设置自定义映射属性&#xff1a;id&#xff1a;表示自定义映射的唯一标识type&#xff1a;查询的数据要映射的实体类的…...

mysql的锁和事务

mysql的锁 读写锁&#xff1a; 读锁是共享锁&#xff0c;多个用户在同一时刻可以读取同一资源&#xff0c;相互不受干扰写锁是排他锁&#xff0c;写锁会阻塞其他的写锁和读锁&#xff0c;这样可以确保在指定的时间内&#xff0c;只有一个用户可以写入 锁的颗粒度&#xff1a; …...

为什么B站中的弹幕可以不遮挡人物

上班逛B站时摸鱼时&#xff0c;看到了满屏的弹幕&#xff0c;而且还不挡脸&#xff0c;突然心血来潮来看看它是怎么实现的&#xff1f; 不难发现弹幕其实它就是有一个蒙版层div&#xff0c;遮挡在视频组件的上方&#xff0c;z-index层级设置的比较高&#xff08;这里是11&…...

数据结构 第八章 查找(静态查找表)

集合 1、集合中的数据元素除了属于同一集合外,没有任何的逻辑关系 2、在集合中,每个数据元素都有一个区别于其他元素的唯一标识(键值或者关键字值) 3、集合的运算&#xff1a; 1 查找某一元素是否存在(内部查找、外部查找) 2 将集合中的元素按照它的唯一标识进行排序4、集合的…...

【Python基础】数据类型(元组、列表)

文章目录二. 数据类型2.1 元组 tuple2.1.1 定义特性2.1.2 拼接拷贝2.1.3 元组拆包2.1.4 元组方法 count2.2 列表 list2.2.1 基础定义2.2.2 增删操作2.2.3 连接联合2.2.4 其他常规操作2.2.5 列表推导式2.2.6 生成器表达式2.x 小结&#xff1a;何时使用元组或列表二. 数据类型 Py…...

你了解互联网APP搜索和推荐的背后逻辑么?

1.搜索和推荐无处不在我们习惯了百度、Google、360搜索的便捷&#xff0c;输入你想要搜索的关键词&#xff0c;立马呈现给你一批对应的结果&#xff0c;供你筛选。我们也经常上淘宝、京东、拼多多购物&#xff0c;输入想买的商品&#xff0c;瞬间列出一页一页的商品清单供我们选…...

Bug的级别,按照什么划分

Bug分类和定级一、bug的定义二、bug的类型三、bug的等级四、bug的优先级一、bug的定义一般是指不满足用户需求的则可以认为是bug&#xff0c;狭义指软件程序的漏洞或缺陷&#xff0c;广义指测试工程师或用户提出的软件可改进的细节、或与需求文档存在差异的功能实现等对应三个测…...

微服务项目简介

项目简介 项目模式 电商模式&#xff1a;市面上有5种常见的电商模式&#xff0c;B2B、B2C、 C2B、 C2C、O2O; 1、B2B模式 B2B (Business to Business)&#xff0c;是指 商家与商家建立的商业关系。如:阿里巴巴 2、B2C 模式 B2C (Business to Consumer), 就是我们经常看到的供…...

SLAM中坐标轴旋转及ros的接口解释

读完几个loam算法&#xff0c;满篇的坐标轴旋转&#xff0c;还是手写的(作者&#xff0c;用eigen写不好嘛。。。)&#xff0c;我滴天适应了好久…&#xff0c;今天就总结一下坐标轴旋转问题。 一、首先&#xff0c;我们看一下ros中关于欧拉角旋转的函数&#xff1a;setRPY、set…...

文件管理(9)

文件管理 0 引言 为什么要引入文件系统&#xff1f; 信息管理的需要&#xff1a;用户面前提供一种规格化的机制&#xff0c;方便用户对文件的存取、提高效率。操作系统本身需要–操作系统本身也不是常驻内存的&#xff0c;也有大量的信息需要存于外存。 1 文件定义 文件&a…...

PyTorch学习笔记:nn.TripletMarginLoss——三元组损失

PyTorch学习笔记&#xff1a;nn.TripletMarginLoss——三元组损失 torch.nn.TripletMarginLoss(margin1.0, p2.0, eps1e-06, swapFalse, size_averageNone, reduceNone, reductionmean)功能&#xff1a;创建一个三元组损失函数(triplet loss)&#xff0c;用于衡量输入数据x1,x…...

冒泡排序详解

冒泡排序是初学C语言的噩梦&#xff0c;也是数据结构中排序的重要组成部分&#xff0c;本章内容我们一起探讨冒泡排序&#xff0c;从理论到代码实现&#xff0c;一步步深入了解冒泡排序。排序算法作为较简单的算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&am…...

git极快上手指南超级精简版

注&#xff1a;本文参考https://www.liaoxuefeng.com/wiki/896043488029600 原文非常值得一读&#xff0c;作者学识渊博&#xff0c;补充了很多有意思的知识。我仅仅是拾人牙慧。 git是最先进的分布式版本控制系统。 版本控制系统——自动记录系统中文件的改动情况&#xff0…...

蓝桥杯-最长公共子序列(线性dp)

没有白走的路&#xff0c;每一步都算数&#x1f388;&#x1f388;&#x1f388; 题目描述&#xff1a; 已知有两个数组a,b。已知每个数组的长度。要求求出两个数组的最长公共子序列 序列 1 2 3 4 5 序列 2 3 2 1 4 5 子序列&#xff1a;从其中抽掉某个或多个元素而产生的新…...

GO的并发模式Context

GO的并发模式Context 文章目录GO的并发模式Context一、介绍二、Context三、context的衍生四、示例&#xff1a;Google Web Search4.1 server程序4.2 userip 包4.3 google 包五、使用context包中程序实体实现sync.WaitGroup同样的功能&#xff08;1&#xff09;使用sync.WaitGro…...

《Redis实战篇》六、秒杀优化

6、秒杀优化 6.0 压力测试 目的&#xff1a;测试1000个用户抢购优惠券时秒杀功能的并发性能~ ①数据库中创建1000用户 这里推荐使用开源工具&#xff1a;https://www.sqlfather.com/ &#xff0c;导入以下配置即可一键生成模拟数据 {"dbName":"hmdp",…...