后端知识积累

Java

  1. java 的5中创建方式
1. new关键字
2. Class.newInstance
3. Constructor.newInstance
4. Clone方法
5. 反序列化
  1. HashSet是如何做到不重复的?
    HashSet是如何做到不重复的?
    HashSet中保证元素不重复的机制就是通过哈希表中的HashCode和equals方法实现的。

  2. 类是如何加载的?

类加载的过程主要分为三个部分:
加载
链接
初始化
而链接又可以细分为三个小部分:
验证
准备
解析
  1. JVM虚拟机的主要模块有哪些?分别的作用是什么?
VM包含两个子系统和两个组件,两个子系统为Class loader(类装载器)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地库接口)。
Class loader(类加载器):根据给定的全限定名类名(如:java.lang.Object)来装载class文件到运行时数据区中的方法区;
Execution engine(执行引擎):执行引擎也叫解释器,负责解释命令,交由操作系统执行;
Native Interface(本地接口):与native libraries交互,是其它编程语言交互的接口。
Runtime data area(运行时数据区域):这就是我们常说的JVM的内存,我们所有所写的程序都被加载到这里,之后才开始运行。

MQ

  1. 消息的幂等性
常用的业务幂等性保证方法
1、利用数据库的唯一约束实现幂等
比如将订单表中的订单编号设置为唯一索引,创建订单时,根据订单编号就可以保证幂等
2、去重表
这个方案本质也是根据数据库的唯一性约束来实现。其实现大体思路是:首先在去重表上建唯一索引,其次操作时把业务表和去重表放在同个本地事务中,如果出现重现重复消费,数据库会抛唯一约束异常,操作就会回滚
3、利用redis的原子性
每次操作都直接set到redis里面,然后将redis数据定时同步到数据库中
4、多版本(乐观锁)控制
此方案多用于更新的场景下。其实现的大体思路是:给业务数据增加一个版本号属性,每次更新数据前,比较当前数据的版本号是否和消息中的版本一致,如果不一致则拒绝更新数据,更新数据的同时将版本号+1
5、状态机机制
此方案多用于更新且业务场景存在多种状态流转的场景
6、token机制(全局唯一id)
生产者发送每条数据的时候,增加一个全局唯一的id,这个id通常是业务的唯一标识,比如订单编号。在消费端消费时,则验证该id是否被消费过,如果还没消费过,则进行业务处理。处理结束后,在把该id存入redis,同时设置状态为已消费。如果已经消费过了,则不进行处理。

Mybatis

  1. MyBatis中在Mapper中如何传递多个参数?
1、若Dao层函数有多个参数,那么其对应的xml中,#{0}代表接收的是Dao层中的第一个参数,#{1}代表Dao中的第二个参数,以此类推。
2、使用@Param注解,在Dao层函数的参数前面添加@Param注解来显式指定每个参数的名称,例如:
3、将多个参数封装成Map并传递到Mapper中,例如:
4、如果Dao层函数传递的是一个对象,该对象包含多个参数,MyBatis会将该对象看做是一个参数,并且会自动地将对象中的属性值映射到
  1. mybatis的4种分页方式(物理分页、逻辑分页)
    1、借助Sql语句Q进行分页(物理分页)
    2、拦截器分页(物理分页)通过拦截器给sq语句末尾加Eimt语句来查询
    3、借助 数组Q进行分页(逻辑分页)
    4、RowBounds分页插件实现分页(逻辑分页)

  2. MyBatis中如何处理like?

1、使用$符号:它可以进行拼接,但会有sql注入的问题
2、在传入name属性,就设置为‘%李白%’,然后使用#符号
3、使用mybatis的bind标签

Spring是线程安全的吗?

1、Spring中Bean从哪里来的?
在Spring容器中,除了很多Spring内置的Bean以外,其他的Bean都是我们自己通过Spring配置来声明的,然后,由Spring容器统一加载。我们在Spring声明配置中通常会配置以下内容,如:class(全类名)、id(也就是Bean的唯一标识)、 scope(作用域)以及lazy-init(是否延时加载)等。之后,Spring容器根据配置内容使用对应的策略来创建Bean的实例。因此,Spring容器中的Bean其实都是根据我们自己写的类来创建的实例。因此,Spring中的Bean是否线程安全,跟Spring容器无关,只是交由Spring容器托管而已。
那么,在Spring容器中,什么样的Bean会存在线程安全问题呢?回答,这个问题之前我们得先回顾一下Spring Bean的作用域。在Spring定义的作用域中,其中有 prototype( 多例Bean )和 singleton ( 单例Bean)。那么,定义为 prototype 的Bean,是在每次 getBean 的时候都会创建一个新的对象。定义为 singleton 的Bean,在Spring容器中只会存在一个全局共享的实例。基于对以上Spring Bean作用域的理解,下面,我们来分析一下在Spring容器中,什么样的Bean会存在线程安全问题。
2、Spring中什么样的Bean存在线程安全问题?
我们已经知道,多例Bean每次都会新创建新实例,也就是说线程之间不存在Bean共享的问题。因此,多例Bean是不存在线程安全问题的。
而单例Bean是所有线程共享一个实例,因此,就可能会存在线程安全问题。但是单例Bean又分为无状态Bean和有状态Bean。在多线程操作中只会对Bean的成员变量进行查询操作,不会修改成员变量的值,这样的Bean称之为无状态Bean。所以,可想而知,无状态的单例Bean是不存在线程安全问题的。但是,在多线程操作中如果需要对Bean中的成员变量进行数据更新操作,这样的Bean称之为有状态Bean,所以,有状态的单例Bean就可能存在线程安全问题。
所以,最终我们得出结论,在Spring中,只有有状态的单例Bean才会存在线程安全问题。我们在使用Spring的过程中,经常会使用到有状态的单例Bean,如果真正遇到了线程安全问题,我们又该如何处理呢?
3、如何处理Spring Bean的线程安全问题?
处理有状态单例Bean的线程安全问题有以下三种方法:
1、将Bean的作用域由 “singleton” 单例 改为 “prototype” 多例。
2、在类中定义 ThreadLocal 的成员变量,并将需要的可变成员变量保存在 ThreadLocal 中,ThreadLocal 本身就具备线程隔离的特性,这就相当于为每个线程提供了一个独立的变量副本,每个线程只需要操作自己的线程副本变量,从而解决线程安全问题

Spring

spring 事务什么时候会失效

Spring事务失效的9种情况
1.事务方法不是public修饰的时候,不支持事务
解决方法:
1)修改成public方法
2)开启 AspectJ代理模式

注意点:
spring声明式事务是基于AOP,AOP的实现原理是动态代理,要通过代理的方式获取到代理的具体对象。如果方法无法重写,就无法被代理。所以static和final修饰方法也同样不能支持事务。

2.@Transactional注解的方法不是抛出的异常不是spring的事务支持的异常,导致事务失败
解决方法:
1)在注解上指定spring支持的异常类型,代码格式为@Transactional(rollbackFor=Exception.class)
2)抛出spring支持回滚的异常,比如:try…cache(Exception e){Throw new RuntimeException(“运行时异常”)}

注意点:
spring的事务只支持未检查异常(unchecked),不支持已检查异常(checked),比如IOException,这些异常在java语法中是要求强制处理的。对于这些普通异常,Spring默认它们都已经处理,所以默认不回滚;

3.数据库本身不支持事务,导致事务失败
解决办法:
比如mysql使用myIsam引擎不支持事务,修改成innodb引擎

4.@Transactional注解所在的类没有被Spring管理,导致事务失效
案例:

//@Service
public class UserServiceImpl implements UserService{
    @Transactional
    public void insertUser(){
        ……
    }
}

解决方法:
添加@Service注解或者其他能注册成spring bean的注解

注意点: 所以必须在实现类等里实现事务

5.catch异常后,没有再次抛出异常,导致事务失效
案例:

@Service
public class UserServiceImpl implements UserService{
    @Transactional
    public void insertUser(){
        try {
            ……
        } cache (Exception e) {
            e.printStackTrace();
        }
    }
}

解决方法:
cache捕获异常后,再次抛出支持Spring事务的异常,比如:

@Service
public class UserServiceImpl implements UserService{
    @Transactional
    public void insertUser(){
        try {
            ……
        } cache (Exception e) {
            throw new RuntimeException();
        }
    }
}

注意点: 如果在加有事务的方法内,使用了try…catch…语句块对异常进行了捕获,而catch语句块没有throw new
RuntimeException异常或者Spring支持的异常类型,则事务不会回滚。

6.调用自身的方法,导致事务失效
案例:

@Service
public class UserServiceImpl implements UserService{
    public void insertUser(){
        insertUserSub();
    }
    @Transactional
    public void insertUserSub(){
        userDao.inserUserSub();
    }
}

解决办法:
1)把insertUserSub方法放到另一个类里
2)自己注入自己,用注入的实例调用insertUserSub方法

@Service
public class UserServiceImpl implements UserService{
    @Autowired
    UserService usertService
    public void insertUser(){
        userService.insertUserSub();
    }
    @Transactional
    public void insertUserSub(){
        userDao.inserUserSub();
    }
}
3)获取代理类,用代理类调用insertUserSub方法

@Service
public class UserServiceImpl implements UserService{
    @Autowired
    UserService usertService
    public void insertUser(){
       ((UserService)AopContext.currentProxy()).insertUserSub();
    }
    @Transactional
    public void insertUserSub(){
        userDao.inserUserSub();
    }
}
4)把@Transactional注解放在inserUser方法上

注意点: @Transactional是基于动态代理实现的,自己调用自己的过程,不存在代理对象的调用,导致事务失效

7.数据源没有配置事务管理器,导致事务失效
解决方法: 增加事务管理器的配置
例如代码没有配置

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
 return new DataSourceTransactionManager(dataSource);
}
1
2
3
4
8.传播类型不支持事务,导致事务失效
实例:

@Service
public class UserServiceImpl implements UserService{
    @Transactional
    public void insertUser(){
        insertUserSub();
    }
    @Transactional(propagation=Propagation.NO_SUPPORTED)
    public void insertUserSub(){
        userDao.inserUserSub();
    }
}
9.多线程调用,导致事务失效
案例:
@Service
public class UserServiceImpl implements UserService{
    @Transactional
    public void insertUser(){
        userDao.inserUser();
        new Thread (() ->{
            roleService.insertRole();
        }).start();
        
    }
}
@Service
public class RoleServiceImpl implements RoleService{
    @Transactional
    public void insertRole(){
        roleDao.inserRole();
    }
}

两个方法不在同一个线程,获取的数据库连接不一样,从而是两个不同的事务。我们说的同一个事物,其实是指同一个数据库连接,只有拥有同一个数据库连接才能同时提交和会滚。

Spring IOC、AOP的原理?

Spring是一个开源的轻量级企业应用开发框架,基于IOC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)的机制实现了对企业级应用开发的支持。下面分别介绍Spring IOC和AOP的原理。

Spring IOC的原理
Spring IOC的核心原理是依赖注入(Dependency Injection,DI),它可以将对象之间的依赖关系交由Spring容器来负责管理,从而实现了对象的解耦。具体来说,Spring IOC的原理包括以下几个方面:

Bean的定义:在Spring容器中,每个需要管理的对象都被称为Bean,可以通过XML配置文件、注解或Java代码等方式进行定义。

Bean的实例化:在Spring容器初始化时,会根据Bean的定义信息创建Bean的实例,并将其存储在容器中。

Bean的注入:在Bean实例化完成后,Spring容器会根据Bean的定义信息,自动将依赖关系注入到Bean中,从而实现了对象之间的解耦。

Bean的作用域:在Spring容器中,每个Bean都有一个作用域,可以是Singleton、Prototype、Session、Request等,通过作用域的设置,可以控制Bean的生命周期和可见性。

Spring AOP的原理
Spring AOP的核心原理是动态代理(Dynamic Proxy)和切面(Aspect),它可以通过在运行时动态地将代码注入到目标对象的方法中,从而实现了横切关注点的统一处理。具体来说,Spring AOP的原理包括以下几个方面:

切面(Aspect)的定义:在Spring AOP中,切面是一个横切关注点的模块化实现,可以通过XML配置文件、注解或Java代码等方式进行定义。

连接点(Join Point)的定义:在Spring AOP中,连接点是指目标对象中可以被切面拦截的方法,可以通过切点(Pointcut)进行定义。

通知(Advice)的定义:在Spring AOP中,通知是在连接点上执行的代码,主要包括前置通知(Before)、后置通知(After)、环绕通知(Around)、异常通知(AfterThrowing)和最终通知(AfterReturning)等。

切面的织入(Weaving):在运行时,Spring容器会将切面中定义的通知动态地织入到目标对象的方法中,从而实现了横切关注点的统一处理。

总体来说,Spring IOC和AOP的原理都是基于Java的反射机制和动态代理机制实现的,通过将对象之间的依赖关系和横切关注点交由Spring容器来管理,从而实现了程序的松耦合和模块化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值