最近线上面试,遇到了个使用GPT大模型面试的

文摘   2024-11-07 09:00   广东  

闲谈

大家好,我是了不起,最近了不起在当面试官,可以说是最直接的接触行情了,每天都会遇到很多情况。

前两天线上面试一个人,最后发现他使用gpt在面试,一开始不正面回答问题,一直在跟我扯“你说的是XXX的那个吗?我听的不太清楚”一类的,支支吾吾拖延时间,十来秒之后又什么问题都能答上来。

随后了不起特地问了个跨行业的技术问题(电力通讯),他不知道超纲了,但是也在支支吾吾十来秒后回答上了。

算了,不提也罢,回归正题,分享一道我最近常用来面试1-2年工作经验的面试题吧。

什么是Spring事务?

Spring事务管理是企业级应用开发中的关键技术之一,确保数据一致性和完整性。

Spring提供了灵活且强大的事务管理机制,通过声明式和编程式的方式让开发者轻松管理事务,同时解耦业务逻辑与事务控制。

Spring的事务管理涵盖了事务的开始、提交、回滚等过程,并为不同的持久化技术(如JDBC、JPA、Hibernate等)提供了统一的事务管理。

在Spring中,声明式事务管理通常使用@Transactional注解来实现。这个注解可以应用到类级别或方法级别,用于指定事务的行为。

比如:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public UserService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Transactional
    public void createUser(String name, String email) {
        String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
        jdbcTemplate.update(sql, name, email);

        // 模拟一个异常,测试事务回滚
        if ("error".equals(name)) {
            throw new RuntimeException("模拟错误");
        }
    }
}

在这个例子中,createUser方法被标记为@Transactional,这意味着如果在这个方法执行过程中发生任何未捕获的异常,事务将会回滚,从而保证数据的一致性。

一般上面的内容,都用于简单解释什么是Spring事务。

但是面试的时候就没那么简单,面试官往往会问你,Spring事务在什么情况下会失效?

在搞清楚为什么会失效之前,我们需要先明白Spring事务的原理!Spring的@Transactional是基于Spring的AOP机制去实现的,AOP又是基于动态代理实现的,那么第一个答案就出来了,代理失效了,Spring事务就失效了

这个回答属于粗浅的回答,基本上只能满足于应届水平的面试,因为背答案就行了。

但是如果你面的是一至三年工作经验的程序员,面试官可不会就这么放过你。

他会接着问,什么情况下,代理会失效?

这方面,可以由浅到深去回答,

比如最简单的就是:

  1. 事务注解没有被启用,也就是没有在配置类上添加上 @EnableTransactionManagement注解,以及 数据源未配置事务管理器,数据库引擎不支持事务(InnoDB)

  2. 同一个类中,没有事务的A方法,调用了带事务的B方法,而你直接使用的是A方法,即:当在一个事务方法内部调用同一个类中的另一个事务方法时,外部方法的事务不会传播到内部方法,除非使用了特定的传播行为(如REQUIRES_NEW)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public UserService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Transactional
    public void createUser(String name, String email) {
        internalCreateUser(name, email);
    }

    @Transactional
    public void internalCreateUser(String name, String email) {
        String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
        jdbcTemplate.update(sql, name, email);

        if ("error".equals(name)) {
            throw new RuntimeException("模拟错误");
        }
    }
}

在这个例子中,createUser方法调用了internalCreateUser方法。由于它们都在同一个类中,所以internalCreateUser方法的事务配置不会生效。如果internalCreateUser方法抛出异常,事务不会回滚。

解决方案:将internalCreateUser方法移到另一个服务类中,或者使用@Transactional(propagation = Propagation.REQUIRES_NEW)来确保每个方法都有独立的事务。

  1. 异常被捕获但是没有抛出

在这个例子中,createUser方法中的异常被捕获并处理了,但没有重新抛出。因此,事务管理器不会回滚事务。

    @Transactional
    public void createUser(String name, String email) {
        try {
            String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
            jdbcTemplate.update(sql, name, email);

            if ("error".equals(name)) {
                throw new RuntimeException("模拟错误");
            }
        } catch (Exception e) {
            // 异常被捕获但没有重新抛出
            System.err.println("捕获到异常: " + e.getMessage());
        }
    }

解决方案:让异常继续向上抛出,或者显式地调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()来手动设置事务回滚。

  1. rollbackFor属性配置错误

默认情况下,Spring事务只在遇到RuntimeException时回滚,对于其他异常可能无法生效。

@Transactional
public void createUser(String name, String email) throws Exception {
    String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
    jdbcTemplate.update(sql, name, email);

    if ("error".equals(name)) {
        throw new Exception("模拟错误");
    }
}

可以通过在@Transactional注解中添加rollbackFor属性,明确指定需要回滚的异常类型。

@Transactional(rollbackFor = Exception.class)
public void createUser(String nameString emailthrows Exception 
{
    String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
    jdbcTemplate.update(sql, name, email);

    if ("error".equals(name)) {
        throw new Exception("模拟错误");
    }
}
  1. 事务方法不是公共方法

如果事务方法不是用public来修饰,那么事务管理器就无法代理这个方法,事务也就失效了。

举例:

@Transactional
protected void createUser(String name, String email) {
    String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
    jdbcTemplate.update(sql, name, email);

    if ("error".equals(name)) {
        throw new RuntimeException("模拟错误");
    }
}

解决方案:将方法声明为public

@Transactional
public void createUser(String name, String email) {
    String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
    jdbcTemplate.update(sql, name, email);

    if ("error".equals(name)) {
        throw new RuntimeException("模拟错误");
    }
}

总结


Java面试教程
Java面试题、Java教程、Java培训、Java学习、Java开发、Java基础、Java入门,关于Java的一切。
 最新文章