Spring是什么?
Spring就是一个轻量级的控制反转(IOC)和面向切面的(AOP)的框架。
什么是IOC/DI?
- IOC(控制反转):全称为:Inverse of Control。从字面上理解就是控制反转了,将对在自身对象中的一个内置对象的控制反转,反转后不再由自己本身的对象进行控制这个内置对象的创建,而是由第三方系统去控制这个内置对象的创建。
- DI(依赖注入):全称为Dependency Injection,意思自身对象中的内置对象是通过注入的方式进行创建。
那么IOC和DI这两者又是什么关系呢?
IOC就是一种软件设计思想,DI是这种软件设计思想的一个实现。而Spring中的核心机制就是DI。
对AOP的理解?
AOP:全称是 Aspect Oriented Programming 即:面向切面编程。简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
Aop的作用:在程序运行期间,不修改源码对已有方法进行增强。
Aop优势:减少重复代码、提高开发效率、维护方便
AOP的实现方式:使用动态代理技术
对IOC的理解?
BeanFactory和ApplicationContext有什么区别?
- BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的生命周期。
- ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能:
a. 国际化支持
b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”
c. 事件传递:通过实现ApplicationContextAware接口 - 常用的获取ApplicationContext的方法:
FileSystemXmlApplicationContext:从【文件系统】 或者 【classpath的xml配置文件】 创建,参数为配置文件名或文件名数组
ClassPathXmlApplicationContext:从【classpath的xml配置文件】创建,可以从【jar包】中读取配置文件
WebApplicationContextUtils:从web应用的根目录读取配置文件,需要先在web.xml中配置,可以配置监听器或者servlet来实现
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
这两种方式都默认配置文件为web-inf/applicationContext.xml,也可使用context-param指定配置文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myApplicationContext.xml</param-value>
</context-param>
Spring的IoC容器就是一个实现了BeanFactory接口的可实例化类。
事实上, Spring提供了两种不同的容器:一种是最基本的BeanFactory,另一种是扩展的ApplicationContext。
BeanFactory 仅提供了最基本的依赖注入支持,而 ApplicationContext 则扩展了BeanFactory ,提供了更多的额外功能。实例化这两种容器时是有区别的:
public class BeanFactoryTest {
public static void main(String[] args) throws Throwable{
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource res = resolver.getResource("classpath:com/baobaotao/beanfactory/beans.xml");
System.out.println(res.getURL());
BeanFactory bf = new XmlBeanFactory(res);
System.out.println("init BeanFactory.");
Car car = bf.getBean("car",Car.class);
System.out.println("car bean is ready for use!");
car.introduce();
}
}
public class XmlApplicationContextTest {
public static void main(String[] args) {
//如果配置文件放置在类路径下,用户可以优先使用ClassPathXmlApplicationContext实现类
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/baobaotao/context/*.xml");
Car car1 = ctx.getBean("car",Car.class);
//如果配置文件放置在文件系统的路径下,则可以优先考虑使用FileSystemXmlApplicationContext实现类
// ctx = new FileSystemXmlApplicationContext("D:/com/baobaotao/context/*.xml");
// Car car2 = ctx.getBean("car",Car.class);
}
}
ApplicationContext的初始化和BeanFactory有一个重大的区别:
BeanFactory在初始化容器时 并未实例化Bean, 直到第一次访问 某个Bean时才实例目标Bean;
而ApplicationContext则在 初始化应用上下文 时就实例化所有的单实例的Bean。
因此ApplicationContext的初始化时间会比BeanFactory稍长一些.
简述spring bean的生命周期?
spring支持的bean作用域?
- singleton作用域:当把一个Bean定义设置为singleton作用域时,Spring IoC容器中只会存在一个共享的Bean实例,并且所有对Bean的请求(将其注入到另一个Bean中,或者以程序的方式调用容器的getBean()方法),只要id与该Bean定义相匹配,则只会返回该Bean的同一实例,可以理解为单例模式。
- prototype作用域:prototype作用域的Bean会导致在每次对该Bean请求时都会创建一个新的Bean实例。
- request:每次http请求都会创建一个bean,该作用域仅在基于web的SpringApplicationContext情形下有效。
- session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
- global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
注意:缺省的Spring bean 的作用域是singleton。
Spring bean 作用域
spring框架中的单例bean是线程安全的吗?
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。
但实际上,大部分的Spring bean并没有可变的状态(比如Service类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。
总结如下:
- 有状态的bean:对象中有实例变量(成员变量),可以保存数据,是非线程安全的;
有状态的bean,也可以使用原型模式(prototype),每次使用时都会重新生成一个对象,解决了线程不安全的问题; - 无状态的bean:对象中没有实例变量(成员变量),不能保存数据,可以在多线程环境下共享,是线程安全的。;
无状态的Bean适合使用不变模式,即单例模式,这样可以共享实例,提高性能。
spring框架中使用了哪些设计模式及应用场景?
事物的特性(ACID)?
- 原子性(Atomicity):事务原子性是事物的最基本的操作单元,要么全部成功,要么全部失败,不会结束在中间某个环节,事务在执行过程中发生错误,那么就会回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性(Consistency):事务的一致性指的是在一个事务执行之前和执行之后,数据库都必须处于一致性状态。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。
- 隔离型(Isolation):指的是在并发环境中,一个事物的执行不能被另一个事务干扰,当不同的事务同时操纵相同的数据时,每个事务互不影响。并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到其他事务中间状态的数据。
- 持久性(Durability):持久性指的是一个事务一旦被提交,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
spring事物的实现方式原理?
事务这个概念是数据库层面的,Spring只是基于数据库中的事务进行了扩展,以及提供了一些能让程序员更加方便操作事务的方式。
比如我们可以通过在某个方法上增加@Transaction注解,就可以开启事务,这个方法所有的sql都会在一个事务中执行,统一成功或失败。
实现方式:1.编程式的事物;2.申明式的事物(@Transaction注解就是申明式的);
原理:在一个方法上加了@Transaction注解后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当在使用这个代理对象的方法时,如果这个方法上存在@Transaction注解,那么代理逻辑会先把事务的自动提交设置为false,然后再去执行原本的业务逻辑方法,如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务进行提交,如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚。
当然,针对哪些异常回滚,事务是可以配置的。可以利用@Transaction注解中的rollbackFor属性进行配置,默认情况下会对RuntimeException和Error进行回滚。
spring事物的隔离级别?
- read_uncommitted(未提交读)是最低的事务隔离级别,它允许一个事务可以看到另外一个事务还未提交的数据。会发生脏读、不可重复读、幻读。
- read_committed(提交读,不可重复读)保证一个事务提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。会发生不可重复读和幻读会发生
- repeatable_read(可重复读)这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读),保证了同一个事务多次读取同样的记录是一致的。
-
serializable(可串行划)这种事务隔离级别下,脏读、不可重复读、幻读都不会发生,是Spring最高的事务隔离级别。因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。所以性能是最低的。
扩展:数据库的配置隔离级别是Read Commited,而Spring配置的隔离级别是Repeatable Read,请问这是隔离级别是以哪一个为准?以Spring配置的为准,如果Spring设置的隔离级别数据库不支持,效果取决于数据库。
脏读、不可重复读、幻象读概念说明
- 脏读:指当一个事务正字访问数据,并且对数据进行了修改,而这种数据还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据还没有提交那么另外一个事务读取到的这个数据我们称之为脏数据。依据脏数据所做的操作肯能是不正确的。
- 不可重复读:指在一个事务内,多次读同一数据。在这个事务还没有执行结束,另外一个事务也访问该同一数据,那么在第一个事务中的两次读取数据之间,由于第二个事务的修改,导致第一个事务两次读到的数据可能是不一样的,这样就发生了在一个事物内两次连续读到的数据是不一样的,这种情况被称为是不可重复读。
- 幻读:幻读是指当一个事务A读取某一个范围的数据时,另一个事务B在这个范围插入行,A事务再次读取这个范围的数据时,会产生幻行。
spring的事物传播机制?
多个事务方法相互调用时,事务如何在这些方法间传播?
方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响,这种影响具体是什么就由两个方法所定义的事务传播类型所决定。
- REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务。举例说明:如果方法A所在的方法里面的sql没有事务,那么就会与方法B里面的sql事务放在一起,要么同时成功,要么同时失败。如果方法A所在的方法里面的sql有事务,那么方法B所在的方法里面的sql就会加入方法A的sql的事务,要么同时成功,要么同时失败。
- SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行。举例说明:如果方法A所在的方法里面的sql有事务,那么方法B里面的sql则会加入方法A的事务,要么同时成功,要么同时失败。如果方法A所在的方法里面的sql没有事务,那么方法B所在的方法里面的sql就会以非事务运行。
- MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。举例说明:如果方法A所在的方法里面的sql有事务,那么方法B里面的sql则会加入方法A的事务,要么同时成功,要么同时失败。如果方法A所在的方法里面的sql没有事务,那么方法B所在的方法就会抛出异常。
- REQUIRES_NEW:创建一个新事物,如果存在当前事务,则挂起该事务。举例说明:如果方法A所在的方法里面的sql有事务,同时方法B所在的方法里面的sql也有事务,那么先执行方法A里面的事务,再去执行方法B里面的事务。这种情况下,A事务回滚就只是回滚A自己的事务,B亦是如此。
- NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务。举例说明:如果方法A所在的方法里面的sql有事务,那么方法A里面的sql单独在事务里执行,方法B里面的sql一定是以非事务运行。如果方法A里面的sql没有事务,那么方法A与方法B里面的sql都是以非事务方式执行。
- NEVER:不使用事务,如果当前事务存在,则抛出异常。
- NESTED:如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)。举例说明:如果方法A所在的sql有事务,那么方法B所在的sql则会嵌套在方法A的事务中执行。
NESTED和REQUIRES_NEW的区别:
REQUIRES_NEW是新建一个事务并且新开启的这个事务与原事务无关,而NESTED则是当前存在事务时(我们把当前事务称之为父事务)会开启一个嵌套事务(称之为一个子事务)。在NESTED情况下父事务回滚时,子事务也会回滚,而在REQUIRES_NEW的情况下,原有事务回滚,不会影响新开启的事务。
spring事物什么时候会失效?
- 1.数据库引擎不支持事务; 这里以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。
- 2.没有被 Spring 管理
// @Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void updateOrder(Order order) {
// update order
}
}
- 3.方法不是 public 的;@Transactional 只能用于 public 的方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启 AspectJ 代理模式。
- 4.自身调用问题;
@Service
public class OrderServiceImpl implements OrderService {
public void update(Order order) {
updateOrder(order);
}
@Transactional
public void updateOrder(Order order) {
// update order
}
}
update方法上面没有加 @Transactional 注解,调用有 @Transactional 注解的 updateOrder 方法,updateOrder 方法上的事务不生效。
再来看下面这个例子:
@Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void update(Order order) {
updateOrder(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateOrder(Order order) {
// update order
}
}
这次在 update 方法上加了 @Transactional,updateOrder 加了 REQUIRES_NEW 新开启一个事务,那么新开的不生效;
- 5、数据源没有配置事务管理器;
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
- 6、不支持事务
@Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void update(Order order) {
updateOrder(order);
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void updateOrder(Order order) {
// update order
}
}
Propagation.NOT_SUPPORTED: 表示不以事务运行,当前若存在事务则挂起;
- 7、异常被捕捉
@Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void updateOrder(Order order) {
try {
// update order
} catch {
}
}
}
- 8、异常类型错误;
@Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void updateOrder(Order order) {
try {
// update order
} catch {
throw new Exception("更新错误");
}
}
}
这样事务也是不生效的,因为默认回滚的是:RuntimeException,如果你想触发其他异常的回滚,需要在注解上配置一下,如:
@Transactional(rollbackFor = Exception.class)
这个配置仅限于 Throwable 异常类及其子类。
什么是bean的自动装备?有哪些方式?
Spring中bean有三种装配机制:
1.在xml中显式配置;
2.在java中显式配置;
3.隐式的bean发现机制和自动装配。
Spring的自动装配需要从两个操作实现
1.组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
2.自动装配(autowiring):spring自动满足bean之间的依赖(IoC/DI);
自动装配注解
@Autowired 自动装配
按类型装配(默认使用的装配方式)。
按名称装配(结合@Qualifier注解使用)。
@Resource自动装配
Resource默认按照名称自动注入
- 既没指定name,也没指定type,自动按照名称装配(当注解写在字段上时,默认取字段名,当注解写在setter方法上时,默认取属性名进行装配。);如果没有匹配,则退而按照类型装配,找不到则抛出异常。
- 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
- 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
- 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
spring和springmvc和springboot的区别?
1.Spring:是一个开源的 Java 应用框架,主要用于构建企业级应用。它提供了一组高级技术,如依赖注入、声明式事务、AOP 等,帮助开发人员构建应用程序。
2.Spring MVC:是一种用于建立 web 应用程序的模型-视图-控制器(MVC)框架。它是基于 Spring 框架的,并且与 Spring 框架集成。
3.Spring Boot:是一种快速构建独立、生产级的、基于 Spring 框架的应用程序的框架。它提供了自动配置、快速开发等功能,并可以将您的应用程序打包成可执行
springmvc的工作流程?
执行前;当一个请求发来时先进服务器(Tomcat),在服务器中会有拦截器,过滤器啊,等这些功能走完之后,才真正的进入了框架中。
1.用户发来一个请求,首先进入的是前端控制器DispatcherServlet
2.前端控制器将(DispacherServlet)用户发来的请求发送给处理器映射器(HandlerMapping)
3.处理器映射器根据前端控制器发来的用户的请求找到对应符合的控制器(Handler),并且将其封装成处理器执行链,返回给前端控制器。
4.处理器适配器接收到来自前端控制器的执行链后,找到对应执行此执行链的处理器适配器(HandlerAdapter)来调用的具体的控制器(就是说其对应的方法或者逻辑)
5.控制器执行完成后,会返回一个ModelAndView对象给处理器适配器
6.处理器适配器将返回来的ModelAndView对象返回给前端控制器(到这里所有的业务处理过程就要完了,接下就是将结果以页面的的形式相应给用户)
7.前端控制器将返回回来的ModelAndView对象交给视图解析器(ViewResolver),视图解析器根据传过里的View对象解析成对应的页面对象,然后将页面对象和Model对象返回给前端控制器。
8.前端控制器再将返回回来的对象交给视图(View),视图根据传过来的Model对象再一次的对页面进行渲染,然后在返回给前端控制器。
9.前端控制器将完成的结果响应给浏览器,然后浏览器在展现给用户。
springmvc的九大组件?
1、HandlerMapping
2、HandlerAdapter
3、HandlerExceptionResolver
4、viewResolver
5、RequestToViewNameTranslator
6、LocalResolver
7、ThemeResolver
8、MultiPartResolver
9、FlashMapManager
SpringMvc内置的九大组件
mysql聚族索引和非聚族索引的区别?
mysql索引结构,各自的优劣?
索引的设计原则?
- 搜索的索引列,不一定是所要选择的列。也就是说,最适合索引的列是出现在where子句中的列,或者连接子句中指定的列,而不是出现在select关键字后的选择列表中的列。
- 使用唯一索引。考虑某列的分布,索引的列的基数越大,索引的效果越好。例如,对性别M/F列做索引没多大用处。
- 使用短索引。如果是对字符串进行索引,如果有可能应该指定前缀长度。
- 利用最左前缀。尽量将使用频繁且过滤效果好的字段放“左边”;
- 不要过度索引。
- Innodb默认会按照一定的顺序保存数据,如果明确定义了主键,则按照主键顺序保存。如果没有主键,但有唯一索引,就按照唯一索引的顺序保存。如果有几个列都是唯一的,都可以作为主键的时候,为了提高查询效率,应选择最常用访问的列作为主键。另外,innodb的普通 index都会保存主键的键值,所有主键要尽可能选择较短的数据类型。可以看出,应当尽量避免对主键的修改。经过dba的测试,保证主键的递增可以提高插入性能。
mysql锁的类型有哪些?
mysql的执行计划怎么看?
EXPLAIN查看执行计划
索引检查sql性能
事物的基本特性和隔离级别?
1.数据库中事务的四大特性(ACID)
- 原子性(Atomicity)原子性是指事务的不可分割,原子是物理上最小的单位,不能再做分割,事物也是一样不能被分割开来;要么全部执行成功,要么全部失败,是一次完整的操作,不能出现成功一半的情况;
- 一致性(Consistency)一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
- 隔离性(Isolation)隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
- 持久性(Durability)持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
2.隔离级别
在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认Read committed级别。
3.相关的安全性问题
- 脏读
- 不可重复读
- 虚读(幻读)
怎么处理慢查询?
- 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引
- 等等等
如何提高数据库查询的速度?
- 缓存,在持久层或持久层之上做缓存
- 数据库表的大字段剥离
- 恰当地使用索引
- 表的拆分
- 字段冗余
- 从磁盘上做文章:数据存放的在磁盘的内、外磁道上,数据获取的效率都是不一样的;
- 放弃关系数据库的某些特性:引入NoSQL数据库;换种思路存放数据,例如搜索中的倒排表;
ACID靠什么保证的?
- A 原子性 由undo log日志保证,它记录了需要回滚的日志信息,事务回滚是撤销已经成功执行的sql
- C 一致性 由其他三大特性保证、程序代码要保证业务上的一致性
- I 隔离性 由MVCC(多版本并发控制)来保证
- D 持久性 由内存+redo log来保证,mysql修改数据同时在内存和redo log记录这次操作,宕机的时候可以从redo log 恢复。(InnoDb redo log 写盘 ,InnoDB事务进入prepare状态。如果前面prepare成功,binlog写盘,再继续将事务日志持久化到binlog,如果持久化成功,那么InnoDb事务则进入commit状态。(在redo log里面写一个commit记录))
多版本并发控制:多版本并发控制(MVCC)的实现是通过保存数据在某个时间点的快照来实现的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
事务传播性、隔离性与MVCC
什么事MVCC?
什么是MVCC
MVCC,Multi-Version Concurrency Control,多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问;在编程语言中实现事务内存。
mysql主从同步原理?
Mysql主从基本原理,主要形式以及主从同步延迟原理 (读写分离)导致主库从库数据不一致问题的及解决方案
myisam和innodb的区别?
MyISAM 发音为 "my-z[ei]m"; InnoDB 发音为 "in-no-db"
1)InnoDB支持事务,MyISAM不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。
2)MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用
3)InnoDB支持外键,MyISAM不支持
4)从MySQL5.5.5以后,InnoDB是默认引擎
5)InnoDB不支持FULLTEXT类型的索引
6)InnoDB中不保存表的行数,如select count() from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含where条件时MyISAM也需要扫描整个表
7)对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引
8)清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表 9)InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’。)