Skip to content

自我介绍

技术考查点:

  1. 语言表达能力
  2. 逻辑思维能力
  3. 对自身优势和经历的总结能力

回答: 您好,我叫[姓名],毕业于[毕业院校]的[专业]。在校期间,我系统学习了[相关专业课程],并通过[实践项目或实习经历]积累了一定的[专业技能]经验。毕业后,我加入了[上家公司名称],在那里我参与了[主要项目名称],负责[具体工作职责],通过这个项目,我提升了[具体能力提升]。我对[应聘岗位相关技能或领域]有浓厚的兴趣,并且一直在不断学习和研究,希望能加入贵公司,为公司的发展贡献自己的力量。

流程图:

代码示例: 由于自我介绍主要是语言表达,暂无代码示例。

seata如何保证最终一致性的

技术考查点:

  1. 对分布式事务的理解
  2. 对Seata框架的掌握

回答: Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 主要通过 AT(自动补偿)、TCC(Try-Confirm-Cancel)、SAGA 和 XA 四种模式来保证分布式事务的最终一致性。以 AT 模式为例,它是一种无侵入的分布式事务解决方案,其核心思想是在业务数据和回滚日志记录在同一个本地事务中提交,从而保证本地事务的原子性。在全局事务层面,Seata 会通过协调器(TC)来管理各个分支事务的状态,确保在全局事务提交或回滚时,各个分支事务能够正确地执行相应的操作。

流程图:

代码示例:

java
// 引入 Seata 依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

// 在业务方法上添加 @GlobalTransactional 注解
@GlobalTransactional
public void businessMethod() {
    // 业务逻辑
}

保持最终一致性的方案

技术考查点:

  1. 对分布式系统最终一致性的理解
  2. 掌握常见的最终一致性方案

回答: 常见的保持最终一致性的方案有消息队列、TCC 模式、SAGA 模式等。以消息队列为例,它的核心思想是将业务操作拆分成多个步骤,并通过消息队列来异步处理这些步骤。在业务操作执行过程中,将需要处理的消息发送到消息队列中,然后由消费者从消息队列中获取消息并进行处理。通过这种方式,可以保证在出现异常时,消息可以被重试,从而保证最终一致性。

流程图:

代码示例:

java
// 引入 RabbitMQ 依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

// 发送消息到 RabbitMQ
@Autowired
private RabbitTemplate rabbitTemplate;

public void sendMessage(String message) {
    rabbitTemplate.convertAndSend("exchangeName", "routingKey", message);
}

// 消费 RabbitMQ 消息
@RabbitListener(queues = "queueName")
public void receiveMessage(String message) {
    // 处理消息
}

AOP 在项目中的应用

技术考查点:

  1. 对 AOP 编程的理解
  2. 实际项目应用能力

回答: 在项目中,我们使用 AOP 主要实现了以下几个功能:

  1. 日志记录:在方法执行前后记录日志,方便调试和监控。
  2. 权限验证:在方法执行前进行权限验证,确保用户有访问权限。
  3. 事务管理:在方法执行前后进行事务管理,确保数据的一致性。
  4. 性能监控:统计方法的执行时间,分析系统性能。

流程图:

代码示例:

java
// 示例代码:使用 AOP 实现日志记录
@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }

    @After("execution(* com.example.service.*.*(..))")
    public void afterAdvice(JoinPoint joinPoint) {
        System.out.println("After method: " + joinPoint.getSignature().getName());
    }
}

多个 AOP 是如何执行的

技术考查点:

  1. 对 AOP 执行顺序的理解
  2. 对 Spring AOP 原理的掌握

回答: 在 Spring AOP 中,多个 AOP 通知的执行顺序是由 AOP 代理的实现机制决定的。Spring AOP 有两种代理方式:JDK 动态代理和 CGLIB 代理。在 JDK 动态代理中,多个 AOP 通知会按照它们在配置文件或注解中的顺序依次执行;在 CGLIB 代理中,多个 AOP 通知会按照它们在字节码中的顺序依次执行。同时,Spring AOP 还支持通过 @Order 注解来指定 AOP 通知的执行顺序,值越小的通知越先执行。

流程图:

代码示例:

java
// 定义 AOP 通知类 1
@Aspect
@Component
@Order(1)
public class Aspect1 {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice1(JoinPoint joinPoint) {
        System.out.println("Before advice 1");
    }
}

// 定义 AOP 通知类 2
@Aspect
@Component
@Order(2)
public class Aspect2 {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice2(JoinPoint joinPoint) {
        System.out.println("Before advice 2");
    }
}

写代码: map 转 list

技术考查点:

  1. 对 Java 集合框架的掌握
  2. 代码实现能力

回答: 在 Java 中,可以使用多种方式将 Map 转换为 List。以下是几种常见的实现方式:

  1. 将 Map 的键转换为 List
  2. 将 Map 的值转换为 List
  3. 将 Map 的键值对转换为 List

代码示例:

java
import java.util.*;

public class MapToListExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("key1", 1);
        map.put("key2", 2);
        map.put("key3", 3);

        // 将 Map 的键转换为 List
        List<String> keyList = new ArrayList<>(map.keySet());
        System.out.println("Key List: " + keyList);

        // 将 Map 的值转换为 List
        List<Integer> valueList = new ArrayList<>(map.values());
        System.out.println("Value List: " + valueList);

        // 将 Map 的键值对转换为 List
        List<Map.Entry<String, Integer>> entryList = new ArrayList<>(map.entrySet());
        System.out.println("Entry List: " + entryList);
    }
}

Spring 事务什么时候会失效

技术考查点:

  1. 对 Spring 事务管理的理解
  2. 常见的事务失效场景

回答: Spring 事务失效的常见场景有:

  1. 方法不是 public 修饰的,Spring AOP 只对 public 方法进行代理。
  2. 自调用问题,即一个类的方法调用自身的另一个事务方法,由于没有经过代理对象,事务不会生效。
  3. 异常被捕获但没有重新抛出,Spring 事务是基于异常来触发回滚的,如果异常被捕获而没有重新抛出,事务不会回滚。
  4. 事务传播行为配置错误,不同的事务传播行为会影响事务的生效情况。

流程图:

代码示例:

java
@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    @Transactional
    public void updateUser() {
        try {
            userDao.updateUser();
            // 模拟异常
            int result = 1 / 0;
        } catch (Exception e) {
            // 捕获异常但未重新抛出,事务失效
        }
    }
}

this 自调用时如何失效的

技术考查点:

  1. 对 Spring AOP 代理机制的理解
  2. 自调用导致事务失效的原理

回答: 在 Spring 中,事务是通过 AOP 代理来实现的。当一个类的方法调用自身的另一个事务方法时,由于是通过 this 关键字调用的,实际上调用的是目标对象的方法,而不是代理对象的方法,因此不会触发 AOP 代理的事务增强逻辑,导致事务失效。

流程图:

代码示例:

java
@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    @Transactional
    public void method1() {
        // 自调用,事务失效
        this.method2();
    }

    @Transactional
    public void method2() {
        userDao.updateUser();
    }
}

算法题: 有效的括号

技术考查点:

  1. 对栈数据结构的掌握
  2. 算法设计和实现能力

回答: 可以使用栈来解决有效的括号问题。遍历字符串,遇到左括号时将其压入栈中,遇到右括号时,检查栈顶元素是否为对应的左括号,如果是则弹出栈顶元素,否则返回 false。遍历结束后,如果栈为空,则说明字符串中的括号是有效的。

代码示例:

java
import java.util.Stack;

public class ValidParentheses {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for (char c : s.toCharArray()) {
            if (c == '(' || c == '[' || c == '{') {
                stack.push(c);
            } else {
                if (stack.isEmpty()) {
                    return false;
                }
                char top = stack.pop();
                if ((c == ')' && top != '(') || (c == ']' && top != '[') || (c == '}' && top != '{')) {
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }
}