-
@ComponentScan: 用于配置 Spring 在哪些包中扫描组件,使其成为 Spring 管理的 Bean。
-
@Component: 通用的组件注解,用于标识一个类作为 Spring 管理的组件。
-
@Controller: 用于标识一个类作为 Spring MVC 中的控制器。
-
@Service: 用于标识一个类作为业务逻辑层的服务组件。
-
@Repository: 用于标识一个类作为数据访问层的组件。
-
@Configuration: 用于标识一个类作为配置类,用于定义 Bean 的创建方式和配置信息。
-
@Autowired: 自动装配注解,用于在 Spring 中自动装配 Bean。
-
@Qualifier: 与 @Autowired 配合使用,指定要注入的 Bean 的名称。
-
@Value: 用于从属性文件中读取配置值,并注入到 Bean 的属性中。
-
@RequestMapping: 用于映射 HTTP 请求到控制器的处理方法。
-
@RequestParam: 用于提取请求中的参数值。
-
@PathVariable: 用于提取请求 URL 中的模板变量。
-
@ResponseBody: 用于标识方法返回的内容直接作为 HTTP 响应体内容。
-
@ResponseStatus: 用于指定处理器方法的 HTTP 响应状态码。
-
@ExceptionHandler: 用于定义处理特定异常的方法。
-
@Transactional
是 Spring 框架中的一个注解,用于声明一个方法应该被事务管理器所管理。@Transactional
注解修饰的方法必须是public
修饰的,同样的@Transactional
修饰类时,也只有类中使用pulbic
修饰的方法才能成为事务。事务是一组操作,要么全部成功执行,要么全部失败回滚,保证了数据库操作的一致性和完整性。@Transactional
注解可以应用在方法级别或者类级别上。如果应用在方法上,则该方法的所有操作将在一个独立的事务中执行。如果应用在类上,则该类中所有带有@Transactional
注解的方法将共享同一个事务。此外,@Transactional
注解还支持配置事务的传播行为、隔离级别、超时时间等属性,以满足不同业务场景的需求。@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
@Transactional
注解的propagation
和isolation
属性用于配置事务的传播行为和隔离级别,这两个属性可以确保事务操作的一致性和完整性。 -
Propagation(传播行为):指定了事务的传播行为,即一个事务方法被另一个事务方法调用时,事务如何传播。常见的传播行为包括:
REQUIRED
:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。REQUIRES_NEW
:创建一个新的事务,并且暂停当前事务(如果存在的话)。SUPPORTS
:支持当前事务,如果当前没有事务,则以非事务方式执行。NOT_SUPPORTED
:以非事务方式执行操作,如果当前存在事务,则将其挂起。NEVER
:以非事务方式执行操作,如果当前存在事务,则抛出异常。MANDATORY
:支持当前事务,如果当前没有事务,则抛出异常。NESTED
:如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则创建一个新的事务。
-
Isolation(隔离级别):指定了事务的隔离级别,即事务在并发环境下的隔离程度。常见的隔离级别包括:
DEFAULT
:默认的隔离级别,由底层数据库决定。READ_UNCOMMITTED
:允许读取未提交的数据。READ_COMMITTED
:只能读取已提交的数据。REPEATABLE_READ
:在事务执行期间,允许多次读取相同的数据,但是不能读取到其他事务提交的更新。SERIALIZABLE
:最高的隔离级别,确保事务之间的完全隔离,可以防止脏读、不可重复读和幻读。
同一个类中,A方法是非事务性方法,但是B方法是事务性方法,此时A调用B就会导致B的事务失效。
当一个事务方法中抛出了异常,此时该异常通过try...catch
进行了捕获,此时就会导致该方法的事务注解@Transactional
失效。在Service层中,方法中最好不要随便写try...catch
,如果写了则一定要手动抛异常。
spring 的事务是通过LocalThread来保证线程安全的,事务和当前线程绑定,此时开启新线程执行业务,这个新线程的业务就会事务失效,因为事务是基于动态代理的,要想有事务,需要被动态代理。这里提供一种解决方法,可以将新的业务单独封装成一个方法,然后改方法上添加一个@Transactional,或者将这个无法单独抽取到一个类中,将该类交给IOC容器进行管理,这样就能让新线程的业务具有事务了
spring 的事务是通过LocalThread来保证线程安全的
当一个方法被@Transactional注解标记时,Spring会在方法开始时创建一个事务上下文对象,并将其存储在ThreadLocal中。这个事务上下文对象包含了当前事务的状态信息,比如事务的隔离级别、传播行为等。
在方法执行过程中,如果存在嵌套调用或者内部调用其他被@Transactional注解标记的方法,Spring会根据方法的传播行为来决定是开启一个新的事务,还是加入已存在的事务。这些决策都是基于当前线程的事务上下文信息。
当方法执行完成时,Spring会根据事务的执行结果,决定是提交事务还是回滚事务,并清理当前线程的事务上下文。
通过使用ThreadLocal来维护事务上下文,Spring能够确保每个线程都有自己独立的事务状态,并且不会受到其他线程事务的影响,从而实现了事务的线程安全管理。
动态代理
动态代理是一种在运行时生成代理对象的机制,代理对象可以在不改变原始类的情况下,为原始类的方法提供额外的功能。在Spring中,通过JDK动态代理和CGLIB动态代理来实现代理对象的生成。
在事务管理中,Spring通过AOP和动态代理实现了以下步骤:
-
切面定义:定义一个切面,用于声明事务管理的逻辑。在Spring中,可以使用@Transactional注解或者XML配置来定义事务切面。
-
通知定义:在切面中定义事务管理的通知,通常包括事务的开始、提交或回滚逻辑。这些通知可以是前置通知、后置通知、异常通知等,用于在方法执行前后执行额外的逻辑。
-
目标类代理:Spring通过动态代理生成目标类的代理对象,并在代理对象中织入事务管理的通知。对于基于接口的目标类,Spring使用JDK动态代理生成代理对象;对于没有接口的目标类,Spring使用CGLIB动态代理生成代理对象。
-
方法执行:当客户端调用目标类的方法时,实际上是调用了代理对象的方法。在代理对象的方法中,Spring会根据切面定义和通知定义,执行事务管理的逻辑。
通过AOP和动态代理,Spring能够在方法执行前后添加事务管理的逻辑,从而实现了声明式事务管理。这种方式可以提高代码的可读性和可维护性,同时降低了事务管理的复杂度。