spring面试题

文章目录

  • 前言
  • 一、面试题
    • 1、springIOC是什么?
    • 2、springIOC产生的原因:背景
    • 3、spring 中Bean的生命周期:
    • 4、springAOP:
    • 5、Spring框架中的设计模式-太多了
      • 1、单例模式(Singleton Pattern):
      • 2、工厂模式(Factory Pattern):
      • 3、代理模式(Proxy Pattern):
      • 4、模板方法模式(Template Method Pattern):
      • 5、观察者模式(Observer Pattern):
      • 6、策略模式(Strategy Pattern):
    • spring的三级缓存:解决循环依赖问题
      • 流程简述:
      • 详细一些:
        • 源码:
    • spring事务:一个又真又假的命题
      • 概念:
      • Spring中的事务管理解决的问题:
      • Spring事务中的概念
      • 容易让人混淆的概念:
  • 总结
  • 补充
    • Spring IOC 常用注解以及含义:
    • Spring事务注解@Transactional的属性和属性值:
      • 具体代码case


前言

虽然说是为了面试,但是呢我们也得不断学习,先学习思想很重要,只有思想到了,技术什么的我理解用一用,整理一下怎么使用就OK了。
若是还有什么新的面试题,我会补充,也希望大家能留言共同维护

当然可以私聊,我希望能结交一些志同道合的朋友
在这里插入图片描述


一、面试题

1、springIOC是什么?

1、是一种思想,(Inversion of Control:控制反转)而不是一个具体的技术实现
2、IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理,但并不是spring独有
3、简单理解就是在一个Map容器中(并非真的Map)存储了要被调用的类的对象,使用的时候直接用就行,不需要进行new;

2、springIOC产生的原因:背景

历史:

在类A中我们调用类B中的方法:
但是类A中存在很多方法假设10个,在没有spring的时候我们需要再每个方法中
B b = new B(); 在通过b.方法()来实现具体调用的方法,这样我们就需要写十个。

问题:

  1. 代码冗余:每个需要类B的方法都要重复创建实例的代码,导致相同的代码散布在多个位置。
  2. 维护成本高:每次修改类B的构造函数或依赖时,所有创建了类B实例的地方都可能需要更新,这增加了维护成本并且容易引入错误。
  3. 耦合度高:类A直接依赖于类B的具体实现,这导致两者之间的耦合度增加,如果要替换类B或其生成逻辑,会涉及到对类A的大量更改。
  4. 其他:在对象.方法1的时候并不会涉及到说对方法1进行修改,所以这里也算是springIOC为什么能出现的一个小原因,但是我不知道怎样描述才能更准确。

为了解决这些问题,Spring框架引入了IoC(控制反转)原则。借助于IoC容器,我们可以将对象的创建和管理从程序代码中抽象出来,交由容器负责。为了使类A能够使用类B而无需直接实例化,我们要在类A中注入一个类B的引用:

@Service
public class B {
    // 类B的实现
}
@Component
public class A {
    @Autowired
    private B b; // Spring容器注入类B的实例
    // 类A的方法可以使用注入的b引用来调用方法
}

@Service 和 @Component 注解告诉Spring容器,它们修饰的类需要被实例化并纳入Spring容器的管理。
这通常意味着将它们作为Bean进行创建和配置。
@Autowired 注解用于自动注入依赖:告诉Spring容器,在创建类A的实例时,应当自动寻找类型为B的实例,并将其注入到类A的b字段中。
如此,所有类A的方法都能重用这一个由Spring容器提供的类B实例。
另一个选择是@Resource注解,该注解通常按名称进行依赖注入,但也可以配置按类型注入。
使用注解和IoC容器的好处是,我们可以通过简单地更改配置来更换依赖的实现,而无需修改业务逻辑代码。
这降低了类之间的耦合,使应用程序的扩展、维护以及测试更加简便。

3、spring 中Bean的生命周期:

1、Bean定义的解析:

容器通过读取配置来源(如XML文件、注解或者Java配置类)来查找并加载所有的Bean定义(Bean Definitions)。

2、Bean实例化:

容器使用Java反射API创建Bean的实例(通常是通过调用默认构造函数)。

3、依赖注入:

容器为Bean实例的属性注入相应的依赖。

4、Aware接口的处理:

  • setBeanName(String): 设定Bean的名称。
  • BeanFactoryAware.setBeanFactory(BeanFactory): 设定BeanFactory引用。
  • ApplicationContextAware.setApplicationContext(ApplicationContext): 设定ApplicationContext引用。
  • 以及其他的Aware接口,如 EnvironmentAware, ResourceLoaderAware 等,容器会调用对应的setXxx方法。

5、BeanPostProcessor前置处理:

对实现了 BeanPostProcessor 接口的Bean,容器调用
postProcessBeforeInitialization(Object bean, String beanName)方法进行前置处理。
此外,BeanPostProcessors 也实现了 postProcessBeforeInstantiation() 和 postProcessAfterInstantiation() 方法,它们分别在实例化前后调用

6、初始化:

  • InitializingBean.afterPropertiesSet(): 如果Bean实现了 InitializingBean 接口,则调用此方法。
  • 自定义初始化方法:如果Bean定义了init-method属性,容器调用指定的自定义初始化方法。

7、BeanPostProcessor后置处理:

对实现了 BeanPostProcessor 接口的Bean,容器调用
postProcessAfterInitialization(Object bean, String beanName) 方法进行后置处理。
此外,BeanPostProcessors 也实现了
postProcessBeforeInstantiation() 和
postProcessAfterInstantiation() 方法,它们分别在实例化前后调用

8、Bean的使用:

完成上述步骤后,Bean就可以被应用程序使用了。

9、销毁前处理:

对实现了 DestructionAwareBeanPostProcessor 接口的Bean,容器调用
postProcessBeforeDestruction(Object bean, String beanName) 方法。

10、销毁处理:

DisposableBean.destroy(): 如果Bean实现了 DisposableBean 接口,则在容器关闭时调用此方法。
自定义销毁方法:如果Bean定义了destroy-method属性,容器在关闭时调用指定的自定义销毁方法。

11、容器关闭:

最后,当应用结束,容器被关闭时,所有单例Bean的清理工作将会被触发。

请注意,以上描述的是Bean的典型生命周期,但实际过程可能会因使用不同的Bean作用域(如单例、原型等)而有所差别。
在原型作用域中,Spring容器不管理一个Bean的完整生命周期,容器会创建Bean实例,进行初始化,然后将其交给客户端代码,不负责销毁。
而在单例作用域中,上述所描述的生命周期是完整的。

4、springAOP:

建议看这篇文章:动态代理——既有落地也有思想
先理解动态代理是什么在学习这个
简而言之就是:
1、动态代理
2、什么时候植入代码:编译时植入、运行时植入等等
3、怎么使用其实就是那几个注解:
看这篇文章:springAOP落地实现

5、Spring框架中的设计模式-太多了

1、单例模式(Singleton Pattern):

  • 在Spring中,单例模式通过Bean的默认作用域实现。每个Spring管理的Bean默认为单例,意味着每次请求都会获得相同的实例。

  • 源码体现:DefaultSingletonBeanRegistry 类中的 singletonObjects 缓存存放着Bean的单例实例。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry {
    // 单例对象的高速缓存
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
    // 省略其他部分

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        // 省略事务代码
        return singletonObject;
    }
}

2、工厂模式(Factory Pattern):

Spring使用工厂模式用于Bean的创建。BeanFactory 是一个工厂接口,它定义了获取Bean的方法。

源码体现:BeanFactory 接口定义了获取Bean的操作。

public interface BeanFactory {
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    // 省略其他部分
}

3、代理模式(Proxy Pattern):

  • Spring AOP使用了代理模式。它通过JDK代理或CGLIB代理在运行时创建Bean的代理,以增加切面逻辑。

  • 源码体现:JdkDynamicAopProxy 类使用了JDK动态代理技术。

public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
    // 使用JDK代理实现AOP的相关代码
    
    public Object getProxy(ClassLoader classLoader) {
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在调用具体的目标方法之前或之后加入增强的代码
    }
}

4、模板方法模式(Template Method Pattern):

  • Spring中的JdbcTemplate和HibernateTemplate等类使用了模板方法模式。它们定义了算法的骨架,将算法的一些步骤延迟到子类中实现。

  • 源码体现:JdbcTemplate 中的 execute 方法。

public abstract class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
    public <T> T execute(StatementCallback<T> action) throws DataAccessException {
        // 初始化和清理代码
        try {
            Statement stmt = con.createStatement();
            return action.doInStatement(stmt);
        } finally {
            // 资源释放代码
        }
    }
    // 省略其他部分
}

5、观察者模式(Observer Pattern):

  • Spring事件处理机制使用观察者模式,允许Bean监听应用事件。

  • 源码体现:ApplicationEventMulticaster 用于事件的广播。

public interface ApplicationEventMulticaster {
    void addApplicationListener(ApplicationListener<?> listener);
    void multicastEvent(ApplicationEvent event);
}

6、策略模式(Strategy Pattern):

  • Spring中资源访问策略,如资源加载Resource和资源解析ResourceLoader。Spring允许不同的策略用于不同类型的资源访问。

  • 源码体现:ResourceLoader 接口和它的实现类。

public interface ResourceLoader {
    Resource getResource(String location);
}

public class DefaultResourceLoader implements ResourceLoader {
    public Resource getResource(String location) {
        if (location.startsWith("/")) {
            return new UrlResource(location);
        } else {
            return new FileSystemResource(location);
        }
    }
}

上面仅列出了Spring框架中使用的一些设计模式,并给出了简略的代码示例。在Spring源码的众多部分都可以发现这些设计模式的身影,它们是理解和扩展Spring框架的重要基础。要深入了解这些模式在Spring源码中的应用,建议直接阅读Spring源码,并结合实际的项目场景来加深理解。

spring的三级缓存:解决循环依赖问题

说明:图是我忘了在什么地方截取的了,在我的个人笔记中,今天借鉴一下,若是有人看见可以告诉我一下。侵权则请联系我,我删除
在这里插入图片描述
1、什么叫循环依赖?

public class A {
    private B b;

    public void setB(B b) {
        this.b = b;
    }
}

public class B {
    private A a;

    public void setA(A a) {
        this.a = a;
    }
}

流程简述:

创建A:将A放入三级缓存中,这时发现需要创建B,
创建B:这时B需要A发现三级缓存中有A,将A拿出放入二级缓存中并将三级缓存中的A删掉,
B创建完成,然后接着
再创建A:A创建完成将A放入一级缓存,将二级缓存中的A删掉。

详细一些:

1、开始创建A:

  • Spring容器开始创建Bean A。
  • 在Bean A的创建过程中,容器会将创建A的ObjectFactory放入三级缓存中。

2、处理A的依赖B:

  • 在A的处理过程中,发现A依赖于B,因此容器开始创建Bean B。

3、开始创建B:

  • Spring容器开始创建Bean B。
  • 在Bean B的创建过程中,容器会将创建B的ObjectFactory放入三级缓存中。

4、处理B的依赖A:

  • 在B的处理过程中,发现B依赖于A,容器尝试获取Bean A的实例。
  • 容器在一级缓存中查找Bean A的实例,但此时并未找到。
  • 容器向三级缓存查询,并找到了负责创建A的ObjectFactory。
  • ObjectFactory负责返回A的早期引用(可能是通过代理进行的),这个早期引用随后被放入二级缓存中。
  • 注:三级缓存中的ObjectFactory不会在此时删除。它将保留直到A完全创建好,并初始化完成。

5、B创建完成:

  • B的依赖注入完成后,B的实例将会被放入一级缓存中。

6、继续创建A:

  • A创建过程继续,完成依赖注入(注入B)。

7、A创建完成:

  • 当A完全创建并完成初始化后,它将被放入一级缓存中。
  • 此时A已经在二级缓存中拥有早期引用,那么一级缓存中添加完成后,该早期引用会从二级缓存移除。
  • 最终当A从二级缓存移动到一级缓存后,A在三级缓存中的ObjectFactory也会被移除。

通过上述机制,Spring容器能够解决大多数单例Bean的循环依赖问题。但记住,这种处理方式仅适用于Spring中的单例Bean,且仅限于字段注入(setter注入),对于构造器注入的循环依赖,默认情况下Spring容器无法解决。

源码:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 尝试从singletonObjects缓存中获取Bean实例
    Object singletonObject = this.singletonObjects.get(beanName);
    // 如果一级缓存中不存在,并且当前Bean正在创建中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 二级缓存中获取
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 如果二级缓存中也没有,并且允许提前暴露引用
            if (singletonObject == null && allowEarlyReference) {
                // 从三级缓存中获取对应的ObjectFactory
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 通过ObjectFactory获取Bean的早期引用
                    singletonObject = singletonFactory.getObject();
                    // 将早期引用放入二级缓存,并从三级缓存中移除
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

spring事务:一个又真又假的命题

概念:

在计算机科学中,事务是指一些列操作的执行单元,这些操作要么全部完成,要不全部不完成,这确保了数据的完整性。事务有如下四大特效

  • 原子性(Atomicity): 事务内的所有操作都是一个不可分割的工作单元,它们要么全部成功,要么全部失败回滚。
  • 一致性(Consistency): 事务的执行从一个一致性状态转换到另一个一致性状态,意味着数据库中的数据将始终保持一致性规则。
  • 隔离性(Isolation): 提供了事务的隔离级别,它定义了一个事务可能受其他并发事务影响的程度。
  • 持久性(Durability): 一旦事务提交,则其对数据库的更改应该是永久的,即使系统发生故障也不会丢失。

Spring中的事务管理解决的问题:

  1. 简化事务管理:Spring提供了一致的事务管理接口,可以在不同的事务管理API(如JTA, JDBC, Hibernate等)之间进行切换而不影响业务代码。
  2. 声明式事务和编程式事务:声明式事务通过配置和注解就可以实现,从而使得业务代码不必与事务管理代码耦合。编程式事务则涉及到使用事务管理API编写更加灵活的事务代码,虽然灵活但代码侵入性较高。
  3. 事务同步:Spring事务管理保证了在一个事务上下文中的所有操作都是同步的。
  4. 事务的回滚:Spring能够自动回滚标记为@Transactional并在执行过程中抛出unchecked异常时的事务。

Spring事务中的概念

  • 声明式事务管理:使用注解(@Transactional)或XML配置来管理事务。
  • 编程式事务管理:使用TransactionTemplate或PlatformTransactionManager的API在代码中直接管理事务。
  • 事务传播行为:定义了当一个事务方法被另一个事务方法调用时,事务如何传播(如:REQUIRED, REQUIRES_NEW, SUPPORTS, NOT_SUPPORTED, MANDATORY, NEVER, NESTED)。
  • 事务隔离级别:定义了一个事务可能受其他并发事务影响的程度(如: READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE)。
  • 回滚规则:定义了导致事务回滚的异常类型。

容易让人混淆的概念:

  • 事务传播行为和隔离级别:这两个概念虽然都与事务管理的详细配置有关,但它们解决的问题不同。传播行为关注的是与其他事务的交互;隔离级别关注的是在并发条件下的数据可见性和一致性。
  • 声明式事务管理和编程式事务管理:声明式事务管理隐藏了事务管理相关的代码,因此显得简洁;而编程式事务管理需要显式调用事务API,给了开发者更高的控制力。容易混淆的点在于它们的使用场景和优势。
  • @Transactional注解的继承性:在类或接口上使用@Transactional注解,并不意味着它的所有子类或实现都会继承这个事务属性,实际行为可能取决于Spring版本和配置。
  • Spring支持的回滚行为:默认情况下,Spring只会在遇到运行时异常(unchecked exceptions)时回滚事务,如果要在受检异常(checked exceptions)发生时也进行回滚,需要额外配置。
  • 多个数据源和分布式事务:处理多个数据库连接和分布式事务时,Spring事务管理比较复杂,可能需要集成JTA或相应的分布式事务管理器。
  • spring整合MySQL 其spring本身并不具有事务这个概念,它仅仅是封装了(如JDBC、Hibernate、JPA等)的事务概念,其实际上常用的也仅仅是他的原子性和持久性,当然在特殊场景下也会用到执行和隔离性,但是一般都是默认

总结

补充

Spring IOC 常用注解以及含义:

@Component:

  • 含义:这个注解表明一个类将被Spring IoC容器作为组件类处理,即该类的实例可以由容器创建和管理。
  • 使用:通常标注在类上,作为通用的组件标识,通常与@Autowired结合使用进行依赖注入。
  • 示例:
@Component
public class MyComponent {
    // ...
}

@Service

  • 含义:标注在服务层(业务逻辑层)的类上,其继承自@Component,表明这是一个服务组件。
  • 使用:与@Component作用类似,但意图更明确的指向服务层组件。
  • 示例:
@Service
public class MyService {
    // ...
}

@Repository

  • 含义:标注在DAO(数据访问层)层的类上,用于指示类提供了数据仓库的功能,也继承自@Component。
  • 使用:可以让DAO层的异常透明地转换为Spring的数据访问异常。
  • 示例:
@Repository
public class MyRepository {
    // ...
}

@Controller

  • 含义:标注在MVC控制器类上,通常用于处理web请求,也是@Component的一个特化。
  • 使用:用在Spring MVC中,与@RequestMapping结合使用。
  • 示例:
@Controller
public class MyController {
    // ...
}

@Autowired

  • 含义:标注在字段、构造器或方法上,用于自动装配Bean。
  • 使用:该注解让Spring完成Bean的自动注入。如果有多个相同类型的Bean,可以配合@Qualifier使用来选择具体注入哪一个。
  • 示例:
@Service
public class MyService {
    @Autowired
    private MyRepository repository;
}

@Qualifier

  • 含义:与@Autowired结合使用,指定注入Bean的名称。
  • 使用:当存在多个同类型Bean时,用于消除自动装配过程中的歧义。
  • 示例:
@Autowired
@Qualifier("specificBean")
private MyInterface myBean;

@Resource

  • 含义:和@Autowired相似,用于自动装配Bean,但它是JSR-250的注解。
  • 使用:默认按照名称装配,如果找不到与名称匹配的bean,则按类型装配。
  • 示例:
@Resource(name = "myBean")
private MyInterface myBean;

@Bean

  • 含义:标注在方法上,表明该方法产生一个Bean,并且交给Spring容器管理。方法返回的实例会被注册为一个Bean。
  • 使用:通常用在配置类(带有@Configuration注解的类)中的方法上。
  • 示例:
@Configuration
public class AppConfig {
    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}

@Configuration

  • 含义:标注在类上,指示一个类提供Spring框架的Bean定义信息。
  • 使用:用于定义配置类,配置类可以包含一个或多个@Bean注解方法。
  • 示例:
@Configuration
public class AppConfig {
    // ...
}

这些注解本身体现了Spring IoC的原则以及Spring 框架中的"约定大于配置"的理念,使用者可以通过简单的注解而不是复杂的XML配置来进行Spring的依赖注入和组件声明。

Spring事务注解@Transactional的属性和属性值:

1、value(或者叫transactionManager):

  • 指定使用的事务管理器bean的名字。

2、propagation: 用来设置事务的传播行为。

  • Propagation.REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,就新建一个事务。这是最常见的选择。
  • Propagation.SUPPORTS:如果当前存在事务,就加入该事务;如果当前没有事务,就以非事务的方式执行。
  • Propagation.MANDATORY:如果当前存在事务,就加入该事务;如果当前没有事务,就抛出异常。
  • Propagation.REQUIRES_NEW:新建事务,如果当前存在事务,就把当前事务挂起。
  • Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • Propagation.NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  • Propagation.NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则表现如同REQUIRED。

3、isolation: 定义了数据的隔离级别。

  • Isolation.DEFAULT:使用底层数据存储的默认隔离级别。
  • Isolation.READ_UNCOMMITTED:允许读取尚未提交的变更,可能会导致脏读,不可重复读和幻线问题。
  • Isolation.READ_COMMITTED:保证一个事务修改的数据提交后才能被另一事务读取,避免脏读。
  • Isolation.REPEATABLE_READ:保证在同一个事务里多次读取同样记录的结果是一致的,避免不可重复读。
  • Isolation.SERIALIZABLE:所有的事务串行执行,避免脏读,不可重复读和幻读。

4、timeout: 指定强制回滚之前可以占用的时间。

  • 默认值为-1(使用底层存储的默认值,通常意味着没有超时限制)。
  • 设置为正整数,表示事务可以占用的最大时间(以秒为单位)。

5、readOnly: 指定当前事务是否只读。

  • true:表示这个事务只读取数据但不更新数据,可以帮助数据库引擎优化事务。
  • false:表示这个事务可能会进行数据更新。

6、rollbackFor: 指定哪些异常会触发事务回滚。

7、rollbackForClassName: 与rollbackFor相同,但是指定的是类的全限定名的字符串表示形式。

8、noRollbackFor: 指定哪些异常不会触发事务回滚。

9、noRollbackForClassName: 与noRollbackFor相同,但是指定的是类的全限定名的字符串表示形式。

了解@Transactional注解的这些属性和值,将有助于在开发过程中合理规划事务的边界和行为,实现有效且安全的数据操作。这些属性的组合可以解决不同事务需要之间的冲突,增强了事务管理的灵活性和功能性。

具体代码case

转账操作的例子,使其更加详尽和符合实际场景。考虑到数据库操作,我们将使用Spring Data JPA来定义实体和存储库接口。我们假设有Account实体和对应的repository用于简化数据库操作。

以下是代码示例,包含异常类、实体类、repository接口以及事务性转账服务的详细实现:


// 自定义的业务异常类,表示账户余额不足
public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

// 实体类,表示账户
@Entity
public class Account {
    @Id
    private Long id;

    private BigDecimal balance;

    // 省略了getter和setter方法

    public void withdraw(BigDecimal amount) throws InsufficientFundsException {
        if (balance.compareTo(amount) < 0) {
            throw new InsufficientFundsException("Insufficient funds");
        }
        balance = balance.subtract(amount);
    }

    public void deposit(BigDecimal amount) {
        balance = balance.add(amount);
    }
}

// Spring Data JPA repository,用于处理Account实体的CRUD操作
public interface AccountRepository extends JpaRepository<Account, Long> {
    // 这里可以自定义一些查询方法,但基本CRUD操作已由JpaRepository提供
}

// 服务类,包含转账的业务逻辑
@Service
public class AccountService {
    @Autowired
    private AccountRepository accountRepository;

    /**
     * 事务性的转账操作
     */
    @Transactional(rollbackFor = InsufficientFundsException.class)
    public void transfer(Long fromAccountId, Long toAccountId, BigDecimal amount) throws InsufficientFundsException {
        Account fromAccount = accountRepository.findById(fromAccountId)
                .orElseThrow(() -> new IllegalArgumentException("Invalid fromAccountId"));
        Account toAccount = accountRepository.findById(toAccountId)
                .orElseThrow(() -> new IllegalArgumentException("Invalid toAccountId"));

        fromAccount.withdraw(amount);
        toAccount.deposit(amount);

        accountRepository.save(fromAccount);
        accountRepository.save(toAccount);
    }
}

在这个例子中,transfer方法负责处理两个账户之间的资金转移。其使用@Transactional注解来确保操作的原子性,即:

  • 如果withdraw方法因账户余额不足抛出InsufficientFundsException,整个转账操作应回滚,即不会有任何变更持久化到数据库。
  • 如果操作成功,即withdraw和deposit方法都没有抛出异常,那么这些变更将被保存到数据库中,并且整个事务将被成功提交。
    为了演示事务失败导致的回滚,你可以在转账操作中加入一些临时逻辑,如故意抛出异常,以观察事务的回滚效果。

请注意,为了这个例子的有效执行,你还需要一个配置Spring Data JPA和数据库连接的Spring Boot应用程序,并且Account实体与您的数据库模式相匹配。

最后,我再次强调,事务的管理和回滚行为取决于你的配置和事务管理器。为了使事务回滚正常工作,你还需要在Spring配置文件中确保事务管理器被正确设置。如果使用Spring Boot,默认情况下会自动配置事务管理器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/410970.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何在三维地球上快速拉白模以辅助建筑规划设计?

通过以下方法可以在三维地球上快速拉白模以辅助建筑规划设计。 方法/步骤 下载三维地图浏览器 http://www.geosaas.com/download/map3dbrowser.exe&#xff0c;安装完成后桌面上出现”三维地图浏览器“图标。 2、双击桌面图标打开”三维地图浏览器“ 3、点击“要素标绘”菜…

算法打卡day3|链表篇|Leetcode 203.移除链表元素、 707.设计链表 、 206.反转链表

链表基本概念 定义 链表是一种通过指针串联在一起的线性结构&#xff0c;每一个节点由两部分组成&#xff0c;一个是数据域一个是指针域&#xff08;存放指向下一个节点的指针&#xff09;&#xff0c;最后一个节点的指针域指向null&#xff08;空指针的意思&#xff09;。其…

聚水潭和金蝶云星空接口打通对接实战

聚水潭和金蝶云星空接口打通对接实战 对接系统聚水潭 聚水潭成立于2014年&#xff0c;创始人兼CEO骆海东拥有近三十年传统及电商ERP的研发和实施部署经验。聚水潭创建之初&#xff0c;以电商SaaSERP切入市场&#xff0c;凭借出色的产品和服务&#xff0c;快速获得市场的肯定。随…

谷歌竞价:8个提升谷歌竞价排名营销推广展示方式

伴随着网络广告的高速发展&#xff0c;谷歌竞价排名变成企业品牌推广产品与服务的有效工具。怎样提高谷歌竞价排名推广展示率却是一个值得探究讨论的话题。下面我们就详细介绍8个方式来帮助你提高谷歌竞价排名推广展示率。 方法一&#xff1a;关键字科学研究和选择关键字在谷歌…

扩展坞的新视角与LDR6023AQ的技术革新

一、扩展坞的演变与重要性 扩展坞&#xff0c;这一设备在现代科技中扮演着日益重要的角色。作为连接手机、电脑和其他设备的桥梁&#xff0c;它不仅延伸了设备的功能边界&#xff0c;还为用户提供了更为便捷和高效的操作体验。随着技术的不断进步&#xff0c;扩展坞的种类和功…

PHP开发人员必备工具:提升效率,加速开发!

PHP开发人员必备工具&#xff1a;提升效率&#xff0c;加速开发&#xff01; PHP是一种广泛应用于Web开发的脚本语言&#xff0c;许多开发人员都在使用PHP构建各种类型的应用程序。为了提高开发效率和质量&#xff0c;有许多工具可以帮助PHP开发人员简化工作流程、调试代码、进…

2024.2.27 模拟实现 RabbitMQ —— 网络通信设计(客户端)

目录 需求分析 RabbitMQ 客户端设定 ConnectionFactory&#xff08;连接工厂&#xff09; Connection&#xff08;连接&#xff09; Channel&#xff08;通道&#xff09; 针对 客户端 和 服务器 单元测试 需求分析 RabbitMQ 客户端设定 一个客户端可以有多个模块每个模块…

HuggingFists系统功能介绍(5)--环境资源

模型库 模型库用于管理由HuggingFists系统自己生成的或者外部导入的各种模型。如&#xff1a;HuggingFace网站提供的各类模型可导入该模块进行统一管理及部署。该功能目前在HuggingFists的社区版中并未提供。 环境管理 环境管理-工作节点 环境管理-服务配置 环境管理主要用于与…

KubeSphere 镜像构建器(S2I)服务证书过期解决方案

目前 KubeSphere 所有 3.x.x 版本&#xff0c;如果开启了 DevOps 模块并使用了镜像构建器功能&#xff08;S2I&#xff09;都会遇到证书过期问题。 解决方法 已开启 DevOps 模块 下载这个更新 S2I 服务证书压缩包&#xff0c;上传到任一可以访问 K8s 集群的节点&#xff1b; …

抖店商家每天都需要做什么?这六点内容不能少!新手建议收藏!

大家好&#xff0c;我是电商小布。 在我们开店运营的过程中&#xff0c;每天需要做的事情其实还是挺多的。 想要我们小店稳定长期的发展下去&#xff0c;有哪些必做的内容呢&#xff1f; 今天&#xff0c;小布就根据我们自己做店几年的经验&#xff0c;来带大家详细的了解一…

Linux-实用操作(黑马学习笔记)

各类小技巧&#xff08;快捷键&#xff09; ctrl c 强制停止 ● Linux某些程序的运行&#xff0c;如果想要强制停止它&#xff0c;可以使用快捷键ctrl c ● 命令输入错误&#xff0c;也可以通过快捷键ctrl c&#xff0c;退出当前输入&#xff0c;重新输入 ctrl d 退出或登…

Project_Euler-24 题解

Project_Euler-24 题解 题目 思路 如果是用笔算的话&#xff0c;可以找到这样的规律&#xff1a; 对于下面的这个组合&#xff1a; 0123456789 {0123456789} 0123456789 我们将其看作一种排列情况&#xff0c;然后我们先使用微扰的方式更改变动一下其中的数值&#xff0c;具…

SQL Developer 小贴士:PL/SQL语法分析

对于SQL或PL/SQL中的语法错误和警告&#xff0c;SQL Developer可以用不同颜色的下划波浪线显示。 启用语法分析&#xff0c;可以用菜单Tool>Preferences>Code Editor>Completion Insight>Enable Semantic Analysis Info Tips 例如&#xff0c;以下的代码中&…

linux系统---安装使用nginx

目录 一、编译安装Nginx 1、关闭防火墙&#xff0c;将安装nginx所需要软件包传到/opt目录下 ​编辑2、安装依赖包 3、创建运行用户、组 4、编译安装nginx 5、创建软链接后直接nginx启动 ​编辑 6、创建nginx自启动文件 ​编辑6.1 重新加载配置、设置开机自启并开启服务…

【开源】JAVA+Vue.js实现大病保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统配置维护2.2 系统参保管理2.3 大病保险管理2.4 大病登记管理2.5 保险审核管理 三、系统详细设计3.1 系统整体配置功能设计3.2 大病人员模块设计3.3 大病保险模块设计3.4 大病登记模块设计3.5 保险审核模块设计 四、…

多线程基础说明【基础篇】

目录 &#x1f32d;1.相关概念 &#x1f37f;2.创建和启动线程 &#x1f95e;3.线程安全 &#x1f9c8;4.死锁 &#x1f953;5.线程通信的方法 1.相关概念 1.1程序 为完成特定任务&#xff0c;用某种语言编写的一组指令的集合。即指一段静态的代码&#xff0c;静态对象…

数据结构二叉树顺序结构——堆的实现

二叉树顺序结构——堆的实现 结构体的创建以及接口函数结构体的创建堆的初始化交换函数堆的插入向上调整删除向下调整返回堆的个数返回堆顶数据判断堆是否为空 该文章以大堆作为研究对象 结构体的创建以及接口函数 typedef int HPDateType;//定义动态数组的数据类型 typedef s…

Spring Cloud学习

1、什么是SpringCloud Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序&#xff0c;提供与外部系统的集成。Spring cloud Task&#xff0c;一个生命周期短暂的微服务框架&#xff0c;用于快速构建执行有限数据处理的应用程序。Spring cloud 流应用程…

Oracle ADG相关介绍

文章目录 一、ADG原理1、ADG介绍2、ADG搭建流程 二、ADG相关参数三、增量修复 一、ADG原理 1、ADG介绍 Oracle ADG&#xff08;Advanced Data Guard&#xff09;是Oracle数据库的一项高可用和灾难恢复技术&#xff0c;它通过将数据保持在物理备库中来提供数据保护和容灾能力。…

Odoo系统安装部署并结合内网穿透实现固定域名访问本地ERP系统

文章目录 前言1. 下载安装Odoo&#xff1a;2. 实现公网访问Odoo本地系统&#xff1a;3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件&#xff0c;是一个一站式全功能ERP及电商平台。 开源性质&#xff1a;Odoo是一个开源的ERP软件&#xff0c;这意味着企…
最新文章