mysql
事务的四大特性及数据库隔离级别
补充:A、I、D是手段、C是目的,弄到一块去完全是为了拼凑个单词缩写,奇葩!
Mysql中事务ACID的原理
不可重复读和幻读的区别在那里呢?
不可重复读是修改或者删除,幻读是插入。(sql92标准明确规定的)
优化的大方向
其他
补充:sql与索引–》表、存储引擎–》架构–》数据库配置(连接数、缓存区大小等)–》os和硬件,越往后成本越高,性能提升越慢
执行计划查看
执行计划extra的取值
mysql join 算法
小表驱动大表
索引的分类
MySQL有哪些索引?为什么用B+树?B+树高度如何计算?
聚簇索引和非聚簇索引的区别
聚簇索引的意思为我们的数据和索引是在一起的,非聚簇索引的意思为索引和数据不在一起。在一起的好处在于我们可以通过找到索引就能找到数据,缺点是索引表非常的大。在innodb引擎中,主键就为聚簇索引,其他的索引为非聚簇索引。在myasim引擎中索引为非聚簇索引。非聚簇索引保存的是索引和该数据在物理储存中的位置。找到索引后还需要去物理储存中再次读取数据。所以非聚簇索引在索引建立时需要更小的空间,但是查找还需要多一次读取。
(mysql会将字符串转化为数字,不会把数字转化为字符串)
索引失效的几种情况
联合索引的数据结构
mvcc
分库分表
基因注入法
锁,死锁以及mysql死锁的处理
行锁什么时候升级表锁
innodb和myisam的区别
innodb的内存结构
内存淘汰算法:lru,区别于传统的lru,新访问的页放在末尾37%的位置,防止全表扫描污染
mysql更新语句的执行流程
其他
B树和B+树的区别
(B-树不是B减树,就是B树,因为B树的英文B-tree翻译过来B-树,翻译的误解,其实就是B树)
补充:B+树数据冗余,重复的数据可能出现在几个节点上,叶子节点有指针,范围查询更方便,叶子节点包含数据和索引,且叶子节点包含所有的数据,查询更稳定,而非叶子节点只有索引
gupao课程的第一课
redis
redis为什么这么快?
纯内存操作。
核心是基于非阻塞的 IO 多路复用机制。
C 语言实现,一般来说,C 语言实现的程序“距离”操作系统更近,执行速度相对会更快。
单线程反而避免了多线程的频繁上下文切换问题,预防了多线程可能产生的竞争问题。
持久化
rdb和aop
集群
smart客户端
数据结构
redis内存淘汰策略
补充:
redis默认是no-envicition策略
spring
ioc和aop
其他1
@Tractional失效的原因
事务传播特性
@Service
public class AA {
@Autowired
private CommonMapper1 commonMapper;
@Autowired
private BB bb;
@Transactional(propagation = Propagation.REQUIRED)
public void mu(){
commonMapper.updateMaById();
try {
bb.bb();
} catch (Exception e) {
e.printStackTrace();
}
// int i = 1/0;
}
}
@Service
public class BB {
@Autowired
private CommonMapper1 commonMapper;
@Transactional(propagation = Propagation.NESTED)
public void bb(){
commonMapper.updateMbById();
int i = 1/0;
}
}
补充:a代表外部,b代表内部
两个都是REQUIRED,外部异常都回滚
两个都是REQUIRED,内部异常都回滚,即使外部捕获了也都回滚,捕获后外部的事务提交报错org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
外部REQUIRED,内部REQUIRED_NEW,内部报错没有被外部捕获都会回滚,如果被外部捕获,外部不回滚,内部回滚
外部REQUIRED,内部REQUIRED_NEW,外部报错,内部不回滚,外部回滚
外部REQUIRED,内部NESTED,外部异常都回滚
外部REQUIRED,内部NESTED,内部异常,外部不捕获,都会回滚,如果外部捕获,外部不回滚,内部回滚
@PostConstruct注解详解
BeanFactory和FactoryNean的区别
spring事务的注解配置
mybatis
执行流程
一级和二级缓存
mybatis如何匹配接口方法和xml的sql语句
补充:
最终mappedStatements.get(id)拿到对应的mappedStatement(这个对象有需要的sql),这里的id即是statementId
springmvc
源码解析
如何通过url找到method
补充:
urlMap:key是String(所有url路径,类和方法拼好的,不含有*和?的路径),value是List<RequestMappingInfo>,这个可以理解为url一样的,但是params之类不一样的,所以用集合
handlerMethods:key是RequestMappingInfo(所有的扫描到的路径,也是由类和方法拼好的),value是HandlerMethod(方法的封装)
设计模式
数据结构与算法
分布式
分布式锁
redis分布式锁
分布式事务和CAP
分布式事务atomikos实现
补充:atomikos是2PC(刚性事务)的实现,目前很少用
一致性算法解析
源码
list–Arraylist和linkedlist
hashmap
hashmap的put方法的过程
ConcurrentHashMap
ConcurrentHashMap扩容
threadlocal
其他
其他2
sync和lock
其他
synchronized原理
String的intern方法
多线程
线程池的七大参数
线程池时如何确定线程数目
书上的答案
线程池的运行流程
线程顺序执行
jvm
new Object()到底占几个字节
线上环境 FGC 频繁,如何解决?
oom分析
详细
垃圾收集器的选择
类加载过程
jvm命令
运行时内存区域
常量池
其他
垃圾收集算法
java的四种引用
破坏双亲委派机制
详细
基础知识
Java面试宝典Beta5.0
String、StringBuffer和StringBuilder的区别
深拷贝和浅拷贝
深拷贝和浅拷贝的实现
基础数据类型和包装数据类型的区别
String.intern方法
jdk7和jdk8的区别
补充:concurrentHashmap存在疑问,另,新增了时间的api
输入一个url后发生什么
三次握手和四次挥手
502状态码的意思
tomcat线程池用完了发生什么
异常的分类
java.lang.Throwable
Error错误:JVM内部的严重问题。无法恢复。程序人员不用处理。
Exception异常:普通的问题。通过合理的处理,程序还可以回到正常执行流程。要求编程人员要进行处理。
RuntimeException:也叫非受检异常(unchecked exception).这类异常是编程人员的逻辑问题。应该承担责任。Java编译器不进行强制要求处理。也就是说,这类异常再程序中,可以进行处理,也可以不处理。
非RuntimeException:也叫受检异常(checked exception).这类异常是由一些外部的偶然因素所引起的。Java编译器强制要求处理。也就是说,程序必须进行对这类异常进行处理。
常见异常
错误:
NoClassDefFoundError:找不到 class 定义异常
StackOverflowError:深递归导致栈被耗尽而抛出的异常
OutOfMemoryError:内存溢出异常
1)非受检的:
NullPointerException,ClassCastException,ArrayIndexsOutOfBoundsException,ArithmeticException(算术异常,除0溢出)
2)受检:
Exception,FileNotFoundException,IOException,SQLException.
项目
被调用方如何保证api接口的数据安全
项目的问题及解决方案
1.mybatis的bug
2.热部署类型转换异常
3.jenkins打包缺失文件
微服务统一认证及授权
接口幂等性
需求改了表怎么办
linux
git
团队协作流程
git版本回退命令
假如我们有下面这一串 commit 的历史,我们希望从 a5 回退到 a3。
a1 -> a2 -> a3 -> a4 -> a5
首先在 a5 我们输入 git log 查看 a3 对应的 commit id,是一段很长的字母数字序列,假设前 4 位是 ab42,并且在所有的 commit id 里面是唯一的(方便我们做简写)。
接着执行:
git reset --hard ab42 # commit id 不用写全,写明能够标识该 commit id 的前几位即可
我们还有更方便的方法,可以不用知道 commit id :
git reset --hard HEAD^^
其中 HEAD^^ 标识我们切换会上上一个版本。如果指向切换为上一个版本,也就是 a4,那可以:
git reset --hard HEAD^
reset 的三种模式
--hard:stage区和工作目录里的内容会被完全重置为和指定 HEAD 位置相同的内容。
--soft:保留工作目录和暂存区中未提交的内容,并把重置 HEAD 所带来的新的差异(回滚掉的commit较回滚后最新commit的修改)放进暂存区。
--mixed(默认):工作区、暂存区未提交的内容以及由 reset 所导致的新差异,都会被放进工作区。
springboot
springboot自动装配原理
spring-boot-start.jar的作用
zookeeper
MQ
补充:
1.生产者发送到RabbitMQ(这里所指的 “RabbitMQ” 仅仅是到 Exchange):一般不采用事务机制,而采用Confirm机制
代码如下:(队列和交换机一般在消费端,遵循谁使用谁管理)
@Configuration
public class TemplateConfig {
@Bean
public ConnectionFactory connectionFactory() throws Exception {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
cachingConnectionFactory.setUri(ResourceUtil.getKey("rabbitmq.uri"));
return cachingConnectionFactory;
}
//管理队列、交换机和绑定
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
return new RabbitAdmin(connectionFactory);
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
//Mandatory为true和ReturnCallback一起保证消息被交换机路由但没有匹配不到队列,会调用ReturnCallback
rabbitTemplate.setMandatory(true);
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback(){
public void returnedMessage(Message message,
int replyCode,
String replyText,
String exchange,
String routingKey){
System.out.println("回发的消息:");
System.out.println("replyCode: "+replyCode);
System.out.println("replyText: "+replyText);
System.out.println("exchange: "+exchange);
System.out.println("routingKey: "+routingKey);
}
});
//事务消息,一般不用,也是确保生产者到MQ这条路正常
rabbitTemplate.setChannelTransacted(true);
//confirm机制,生产者发送消息后,MQ会回调,确保生产者到MQ这条路正常
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (!ack) {
System.out.println("发送消息失败:" + cause);
throw new RuntimeException("发送异常:" + cause);
}
}
});
return rabbitTemplate;
}
}
2.Exchange 没有匹配到队列的话,消息依然会丢失:
1)mandatory和ReturnCallback 代码如上
2)备份交换机:交换机的arguments参数alternate-exchange填写创建好的备份交换机(15672管理界面创建交换机)
3.交换机、队列、消息的持久化;
代码如下:
@Configuration
public class ConsumerConfig {
@Bean
public ConnectionFactory connectionFactory() throws Exception{
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
cachingConnectionFactory.setUri(ResourceUtil.getKey("rabbitmq.uri"));
return cachingConnectionFactory;
}
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
return new RabbitAdmin(connectionFactory);
}
//第二个参数为是否持久化
@Bean("reliableQueue")
public Queue queue() {
return new Queue("GP_RELIABLE_SEND_QUEUE", true, false, false, new HashMap<>());
}
//第二个参数为是否持久化
@Bean("directExchange")
public DirectExchange exchange() {
return new DirectExchange("GP_RELIABLE_SEND_EXCHANGE", true, false, new HashMap<>());
}
@Bean
public Binding binding(@Qualifier("reliableQueue") Queue queue,@Qualifier("directExchange") DirectExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("gupao.tech");
}
@Bean
public MessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer messageListenerContainer = new SimpleMessageListenerContainer();
messageListenerContainer.setConnectionFactory(connectionFactory);
messageListenerContainer.setQueueNames("GP_RELIABLE_SEND_QUEUE");
// 消费者并发数
messageListenerContainer.setConcurrentConsumers(5);
// 最大消费者并发
messageListenerContainer.setMaxConcurrentConsumers(10);
Map<String, Object> argumentMap = new HashMap();
messageListenerContainer.setConsumerArguments(argumentMap);
messageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String s) {
return "添加消费者";
}
});
messageListenerContainer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
System.out.println(new String(message.getBody(), "UTF-8"));
System.out.println(message.getMessageProperties());
} catch (Exception e) {
e.printStackTrace();
}
}
});
return messageListenerContainer;
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProducerApp.class);
RabbitAdmin rabbitAdmin = context.getBean(RabbitAdmin.class);
RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
rabbitAdmin.declareExchange(new DirectExchange("GP_RELIABLE_SEND_EXCHANGE", true, false, new HashMap<>()));
MessageProperties messageProperties = new MessageProperties();
// 消息持久化
messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
messageProperties.setContentType("UTF-8");
Message message = new Message("各部门注意,今天8点发车".getBytes(), messageProperties);
rabbitTemplate.convertAndSend("GP_RELIABLE_SEND_EXCHANGE", "gupao.tech", message, new CorrelationData("201906180001"));
rabbitTemplate.send("GP_RELIABLE_SEND_EXCHANGE", "gupao.tech", message, new CorrelationData("201906180001"));
rabbitTemplate.send("GP_RELIABLE_SEND_EXCHANGE", "gupao.tech.wrong", message, new CorrelationData("201906180002"));
}
4.采用镜像模式的集群
5.MQ到消费者,开启手动确认(单独设置某个队列)
代码:
//springboot中消费者被封装为SimpleMessageListenerContainer,可以在这个类上设置
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory){
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames("consumer_queue"); // 监听的队列
container.setAcknowledgeMode(AcknowledgeMode.MANUAL); // 手动确认
container.setMessageListener((ChannelAwareMessageListener) (message, channel) -> { //消息处理
System.out.println("====接收到消息=====");
System.out.println(new String(message.getBody()));
if(message.getMessageProperties().getHeaders().get("error") == null){
//第二个参数为消息是否重新入队,多消费者的时候可以设置为true
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
System.out.println("消息已经确认");
}else {
//channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
System.out.println("消息拒绝");
}
});
return container;
}
或者在消费消息的代码上加上:
@RabbitHandler
public void processMessage2(String message,Channel channel,@Header(AmqpHeaders.DELIVERY_TAG) long tag) {
System.out.println(message);
try {
//第二个参数为消息是否重新入队,多消费者的时候可以考虑设置为true
channel.basicAck(tag,false); // 确认消息
} catch (IOException e) {
e.printStackTrace();
}
}
6.消息落库,对消息进行状态标记
分布式源码
dubbo的spi机制
Feign+Ribbon+Hystrix的原理
总结:@EnableFeignClients里有@Import(FeignClientsRegistrar.class),FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar,导入了批量的bean,
registerBeanDefinitions--》registerFeignClients--》registerFeignClient,由此引入FeignClientFactoryBean,他是FactoryBean,注入的时候会调用getObject方法
getObject--》getTarget--》targeter.target--》不管哪个实现都会进入feign.target(target)
--》newInstance(target)--》factory.create(target, methodToHandler)--》匿名内部类的new InvocationHandlerFactory() 的create方法返回HystrixInvocationHandler,所以注入的对象最终会调用HystrixInvocationHandler的invoke方法,此方法组成HystrixCommand的run和
getFallback,其中run从Map<Method, MethodHandler> dispatch中根据method取到MethodHandler,其实现为SynchronousMethodHandler,并调用他的invoke方法
springboot应用启动扫描导入批量bean的流程
SpringApplication的run、refreshContext、refresh---》AbstractApplicationContext的refresh--》AbstractApplicationContext的invokeBeanFactoryPostProcessors(beanFactory)--》ConfigurationClassParser的processConfigurationClass---》ConfigurationClassParser的doProcessConfigurationClass--》ConfigurationClassParser的processImports
FeignClientsRegistrar深入分析
getObject方法深入分析
feign集成hystrix原理
集成ribbon原理
补充:从SynchronousMethodHandler的invoke方法看起
nacos实现原理