目录
九、MYSQL索引失效的几种场景
一、Redis持久化后,数据会一直不丢失吗
1、RDB 跟持久化策略相关。 save 60 1,60s内执行一次写命令,持久化一次。save 300 10,300s内执行10次写命令,才持久化,假设只执行了5次,宕机了,数据就没了
2、AOF
通过持久化命令保证数据持久化
appendfsunc always 每次执行命令,会将写命令存到内存aof buffer,就将写命令进行持久化
appendfsunc everysec 默认策略,每次执行命令,会将写命令存到内存aof buffer,每隔1s持久化
appendfsunc no 每次执行命令,会将写命令存到内存aof buffer,redis不主动持久化,交由操作系统
默认情况下,AOF也会丢失1s的数据
3、混合(Redis4.0后)
二、Spring中定义bean的方式
1、@Bean
2、@Component
3、@Controller @RestController @Service @Repository
4、ControllerAdvice、@RestControllerAdvice
5、@Configuration 配置bean
可以再去定义一些bean
6、@Import(ProductService.class)
7、BeanDifinition 实现ImportBeanDefinitionRegister 声明一个类
8、<bean/>标签
三、如何理解Spring的自动配置
@EnableAutoConfiguration 自动配置注解生效
@SpringBootConfiguration
@ComponentScan
以上3个注解等于1个注解 @SpringBootApplication
四、@Autowrired和@Resource注解的区别
private ProductService(类型) productService(名字)
@Autowired 先根据类型 ,找到多个在根据名字。是Spring提供的
@Resource 先根据名字找,在根据类型找,找到多个会报错。
如果自定义了名字,就只根据名字找,如@Resource(name="xxxService")
@Inject 也是现根据类型,再跟进名字,它是JDK层面提供的
Online DDL 相当于和其他事务并行,只不过会在表空闲时才会去执行,不会去阻塞其它的语句
五、事务失效的几种情况
@Transaction 代理对象才有效
开启sring事务
事务管理器新建一个数据库连接conn
conn.autocommit=false
普通对象执行test()方法 抛异常 conn.rollback(); 正常 coon.commit
事务失效的情况
1、方法内自调用,spring事务是基础AOP的,只有使用代理对象调用某个方法时才能生效,
而在一个方法中调用使用this.xxx()调用时,this不是代理对象,会导致事务失效。
解决方法:把调用方法拆分到另一个bean里、自己注入自己、
2、方法是private的 Spring事务基于CGLIB来进行AOP,而CGLIB会基于父子类来失效,子类是
代理类,父类是被代理类,如果父类中的某个方法是private的,那么子类就没办法重写它,也就没有办法额外增加Spring事务的逻辑
3、方法是Final的,原因子类不能重新父类的final方法
4、单独的线程调用,不懂----
5、没有加注解,使用SpriongBoot没有这个问题,Spring 下会出现此种情况。原因,mybatis或者JdbcTemplate会从ThreadLocal中获取数据库连接,但是
ThreadLocal中存的是MAp,Map的key为DateSource对象,value为连接对象,如果没有加注解,会导致Map中DateSource对象与Mybatis或JdbaTemplate的不相等,
从而拿不到连接,导致自己去创建数据库连接了,此时的autoCommit为true。
6、异常被吃掉,默认情况下会捕获RunTineException和Error
7、类没有被Spring管理
8、数据库不支持事务
六、多线程
1、Java中有几种方式创建线程
- 继承Thread类
- 实现Runnable接口,实现run()方法
- 实现Callable接口,可以拿到任务结果,结合FutureTask
public class XxxService implement Callable<String> { public static void main(String[] args){ FutureTask<String> futureTask = new FutureTask<>(new XXXThread); Thread thread = new Thread(futureTask ); thread.start(); String result = futureTask.get(); } public String call(){ return "hahah"; }
- 利用线程池创建线程:
- 使用newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- 使用newFixedThreadPool,创建一个指定工作线程数量的线程池。
- 使用newSingleThreadExecutor,创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO,优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。
- 使用newScheduledThreadPool,创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。
为什么不建议使用 Executors来创建线程池?
因为 底层是LinkedBlockedeue无界阻塞队列,执行的任务越多,就会不断地添加到队列中,占用的内存就越多,最终会导致内存耗尽,导致OOM。建议直接使用ThreadPoolExector来定义线程池。
2、线程的几种状态
- Running 表示线程正常运行
- ShutDown 表示线程处于正在关闭状态,不在接受新任务,但是会继续把队列中的任务处理完
- ShutDownNow 表示线程处于正在停止状态,不在接受新任务,也不会处理队列中的任务,并且正在运行的任务也会被中断。
- Diying 线程池中没有线程运行,就会进入Diying状态,并且会调用Terminated()
- TERMINATED Terminated()方法执行完,就进入Terminated()。
3、如何设置线程数
CPU密集时 设置CPU核心数+1;线程执行时,会一直利用CPU,对于这种情况,尽可能减少线程上线文的切换
比如:电脑只有1个CPU,两个线程同时执行找素数的任务,总执行时间为 执行时间*2+线程上下文切换
对于Cpu密集型任务,线程数最好等于CPU核心数,可以通过以下API拿到电脑核心数:
RunTime.getRuntime().availaableProcessors();
4、IO执行时间越长,同时阻塞在IO上的线程数越多,就可以设置更多线程
线程数=CPU核心数*(1+线程等待时间/线程运行总时间) 通常会设置2*线程数
七、Sychronized的锁的升级过程
1、偏向锁
指的是线程获取到了锁之后,在锁的头部会记录一个线程id,下次线程在来获取锁可以直接获取到,也就是锁重入
2、轻量级锁
是由偏向锁升级而来,指的是当一个线程获取到了锁,另一个线程来竞争时,会升级为轻量级锁,底层通过自旋来实现,不会阻塞线程。
3、重量级锁
经过多次自旋,依旧未获取到锁,会升级为重量级锁,此时会堵塞线程
自旋锁:所得 就是线程去获取锁的过程中,不会堵塞线程,也就无所谓锁的唤醒,堵塞和唤醒是操作系统执行的,所以也就不耗费资源。自旋是 通过CAS来获取预期的一个标记,获取到了则获取锁成功,这个过程线程一直是运行的,相对而言没有使用太多操作系统资源,是轻量的。
八、什么是InnerDb中的页
查询时,从磁盘读取数据,放进内存
一页是16KB,一页分为3部分:页头、页目录、存储数据区域
select * from table where a = 3;执行方式,先遍历页目录,在去遍历具体的那一组,通过页目录进一步提高查询效率。
如果插入不是用自增id,会导致以前已经存好的数据,发生改变。比如第一页数据已满(1 2 3 6),这时新增一个数字4,排序应该在第一页,会导致6移动到第二页。
怎么判断数据在第几页?通过索引页判断、找到数据页
九、MYSQL索引失效的几种场景
- 不符合最左匹配原则 提供索引列的最左字段
- LIke百分号左边失效
- 对索引列进行计算、或使用函数
- 索引列进行了类型转换。
比如一个 varchar类型 给了数字。 a=1,索引会失效,mysql会将字段转换成数字
但是如果 a是int类型,a= '1',不会失效,mysql执行时只需要将值转换数字 - order by 回表
- 不等于 <>
- or
- 范围查询数量过大
- select * 导致索引失效