spring的构造注入和set注入的区别
set注入:先实例化对象,再注入。先调对象的构造函数。spring先实例化对象,然后才实例化所有依赖对象。set注入表达了两个对象的较弱依赖关系:聚合关系。
构造注入:先实例化对象需依赖对象,再实例化对象。spring保证一个对象所有依赖对象先实例化后,才实例化这个对象(没有他们就没有我原则)。构造注入表达了2个对象间强的聚合关系:组合关系。
spring无法解决构造注入产生的循环依赖。解决方案:使用@Lazy(对构造入参加此注解),基本思路是:对于强依赖的对象,一开始并不注入对象本身,而是注入其代理对象,以便顺利完成实例的构造,形成一个完整的对象,这样与其他应用层对象就不会形成互相依赖的关系;当需要调用真实对象的方法时,通过TatgetSource去拿到真实的对象,然后通过反射完成调用。
mysql优化
- 选取最合适的字段。
- 使用连接(join)来代替子查询(sub-Querues)
- 使用联合(union)来代替手动创建的临时表。例:select name,pwd from tbl_user union select name,age from tbl_usertest
- 使用索引。索引失效的情况:like前缀匹配、or语句前后没有同时使用索引、组合索引不是使用第一列索引、数据类型出现隐式转换、使用is null 或 is not null、使用not,<>,!=操作符、使用函数、全表扫描比索引快时。
- 小表驱动大表:select * from A wherr id in (select id from B )和 select * from A where exists (select 1 from B where B.id = A.id) 前者和后者的使用场景:前者:当B的数据急小于A时,后者反之。
CAP理论
C:一致性
A:可用性
P:分区容错性
BASE理论
是对CAP中一致性和可用行权衡的结果,是基于CAP定律逐步演化而来。其核心思想是即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
BASE理论使Basically Available(基本可用),Soft State(软状态)和Eventually
Consistent(最终一致性)三个短语的缩写。
其核心思想是:即使无法做到强一致性,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。
软状态是指:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许在多个不同节点的数据副本存在数据延时。
硬状态:相对原子性而言,要求多个节点的数据副本都是一致的。
最终一致性:不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性,从而达到数据的最终一致性。这个时间期限取决于网络延时、系统负载、数据复制方案设计等等因素。
而在工程实践中,最终一致性分为5种:
- 因果一致性:如果节点A在更新完某个数据后通知了节点B,那么节点B之后对该数据的访问和修改都是基于A更新后的值。于此同时,和节点A无因果关系的节点C的数据访问则没有这样的限制。
- 读己之所写:节点A更新一个数据后,它自身总是能访问到自身更新过的最新值,而不会看到旧值。
- 会话一致性:对系统数据的访问过程框定在一个会话当中:系统能保证在同一个有效的会话中实现"读己之所写"的一致性,也就是说,执行更新操作之后,客户端能够在同一个会话中始终读取到该数据项的最新值。
- 单调读一致性:如果一个节点从系统中读取出一个数据项的某个值后,那么系统对于该节点后续的任何数据访问都不应该返回更旧的值。
- 单调写一致性:一个系统要能够保证来自同一个节点的写操作会被顺序的执行。
分布式事务
- 2PC:二阶段提交,是一种强一致性设计,引入一个事务协调者的角色来协调管理各参与者(也可称之为各本地资源)的提交和回滚。第一阶段发送准备命令(不提交),如果参与者全部返回成功,则发送命令提交事务,如有一个参与者提交失败,则发送回滚命令。2PC是一种保证强一致性的分布式事务,因此它是同步阻塞的,二同步阻塞就导致长久的资源锁定问题,总体而言相率低,并且存在单点故障问题,在极端条件下存在数据不一致风险。
- 3PC:三阶段提交,前两个阶段和2PC一样,在第三阶段引入了超时限制。存在于理论中。
- TCC:业务层面的分布式事务,2PC和3PC都是数据库层面的。Try-Confirm-Cancel。预留、确认、撤销。对所有服务执行预留操作,都预留成功执行确认,有一个预留失败执行撤销操作。补偿性事务思想。
- 本地消息表:利用各系统本地的事务来实现分布式事务。有一张存放本地消息的表,一般都是放在数据库中,然后在执行业务的时候将业务的执行和将消息放入消息表中的操作放在同一个事务中,这样就能保证消息放入本都表中业务肯定是执行成功的。然后再去调下一个操作,调用成功,消息表状态改为已成功,失败则会有后台任务定时去读取本地消息表,筛选出还未成功的消息再调用对应的服务,服务更新成功了再变更消息的状态。这时候有可能消息对应的操作不成功,因此也需要重试,重试就得保证对象服务的方法是幂等的,而且一般重试会有最大次数。本地消息表其实实现的是最终一致性,容忍了数据暂时不一致的情况。
- 消息事务:实现最终一致性。
- 最大努力通知:尽力达成事务的最终一致性。
spring事务传播级别
事务传播行为类型 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
数据库隔离级别
隔离级别 | 脏读(Dirty Read) | 不可重复读(NonRepeatable Read) | 幻读(Phantom Read) |
---|---|---|---|
未提交读(Read uncommitted) | 可能 | 可能 | 可能 |
已提交读(Read committed) | 不可能 | 可能 | 可能 |
可重复读(Repeatable read) | 不可能 | 不可能 | 可能 |
可串行化(Serializable ) | 不可能 | 不可能 | 不可能 |
未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据。任何操作都不会加锁。
提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)。数据的读取都是不加锁的,但是数据的写入、修改和删除是需要加锁的。
可重复读(Repeated Read 默认隔离级别):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读。读就是可重读,可重读这个概念是一事务的多个实例在并发读取数据时,会看到同样的数据行。
串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。读加共享锁,写加排他锁,读写互斥。使用的悲观锁的理论,实现简单,数据更加安全,但是并发能力非常差。如果你的业务并发的特别少或者没有并发,同时又要求数据及时可靠的话,可以使用这种模式
mybatis动态sql原理
spring执行流程
- 解析配置文件
- 执行beanFactory的后处理器
- 又beanFactory创建每个类的单例对象,利用反射根据类名创建每个类的实例对象。
- 执行bean的后处理器
- 执行依赖注入
spring bean的生命周期
springmvc执行流程
dispatcherServlet(前端控制器)去handlermapping(处理起映射器)招对应的请求执行对象,请求执行handler,handleradapter(处理器适配器)执行hangler并返回modelandview,modelandview(视图解析器)返回view对象,渲染视图。
mysql的int(1)和int(10)的区别
对值没有影响,只是对值的展示有影响,当长度不足时,会在前面补0,如:int(4)存储10时,显示为 0010
spring什么时候开启事务
执行被事务注解的方法时,会判断是否有必要创建事务。如果事务创建成功,则继续调用业务逻辑方法。事务是在方法执行最开始阶段创建的,因此方法要越小越好。
怎么保证幂等性
唯一索引、token机制、加锁、
redis什么时候删除过期key
被动策略:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除这个过期key。
主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以redis会定期主动淘汰一批已过期的key。
当前已用内存超过maxmemory限定时,触发主动清理策略
mysql什么时候创建行锁什么时候创建表锁(innodb下)
insert时全表锁,update是行级锁(非绝对-成功使用索引时行锁,否则锁表)。
行表锁总结:
表级锁:开销小,吞吐量会减小。
行级锁:开销大,吞吐量也大。
MyISAM只支持表级锁;InnoDB支持行级锁(分为共享锁和排它锁)。可以使用表锁。当前读(出显式in share外,包括update都是排它锁)。
innodb一般情况下走索引或者主键更新都是锁行,其余都是锁表,在并发的时候可以加select for update手工锁。
innodb表,主要有以下几点:
- innodb的行锁是基于索引实现的,如果不通过索引访问数据,innodb会使用表锁。
- innodb间隙锁机制以及innodb使用间隙锁的原因。
- 在不同的隔离级别下,innodb的锁机制和一致性读策略不同。
- mysql的恢复和复制对innodb锁机制和一致性读策略也有较大影响
- 锁冲突甚至死锁很难完全避免。
- 在了解innodb的锁特性后,用户可以通过设计和SQL调整等措施减少锁冲突和死锁,包括:
- List item尽量使用较低的隔离级别(未提交读、已提交读、可重复读、可串行化,默认可重复读)。
- 精心设计索引,并尽量使用索引访问数据,使加锁更精确从而减少锁冲突的机会。细粒度。
- 选择合理的事务大小,小事务发送锁冲突的几率也更小。
- 给记录集显式加锁,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排它锁,而不是先申请共享锁,修改时再请求排它锁,这样容易产生死锁。
- 不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大大减少死锁的机会。
- 尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响。
- 不要申请超过实际需要的锁级别;除非必须,查询时不要显式加锁。
- 对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能。
要修改数据,首先要找到数据,而如果没有索引,就会直接锁住表的数据,就会锁住其他的会话。
innodb行锁时通过索引上的索引项加锁来实现的。 数据库的增删改操作默认都会加排它锁,而查询不会加任何锁。 共享锁:对某一资源加共享锁,自身可以读该资源,其他人也可以读该资源(也可以再继续加共享锁,即
共享锁可多个共存),但无法修改。要想修改就必须等所有共享锁释放完。语法为:select * from table in share
mode。 排它锁:对某一资源加排它锁,自身和增删改查,其他人无法进行任何操作。语法为:slect * from table for
update。
通过反射调用方法
直接反射获取类的class对象,强转直接调
获取类的method对象,通过method的invoke()方法进行调用
mysql聚簇索引
就是索引和数据存放在一个B树中的一种索引,普通索引是只存放索引键字段,指向数据。
String、StringBuffer与StringBuilder之间区别
String | StringBuffer | StringBuilder |
---|---|---|
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间 | StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量 | 可变类,速度更快 |
不可变 | 不可能 | 可能 |
可重复读(Repeatable read) | 可变 | 可变 |
线程安全 | 不可能 | |
多线程操作字符串 | 单线程操作字符串 |
MySQL回表
MySQL对表会维护主键索引,主键索引是聚簇索引,能查到行数据,而普通索引只能查到索引单个字段和主键。回表是你根据普通索引查到主键,再根据主键查询到行数据来获取查询字段。