synchronized 与 spring事务 @Transactional 的介绍使用

简单再介绍一下 synchronized 与 spring 的事务以及两者的配合使用

synchronized

介绍

synchronized 关键字(独占式的悲观锁,同时属于可重入锁)它可以把任意一个非NULL的对象当作锁。

本质上根据属性可以分为对象锁、class锁。

根据使用场景可分为方法锁与代码块锁。

  • 方法锁

作用于普通方法时,锁住的是类对象的实例(this);

**作用于静态方法时,锁住的是类Class实例;**又因为Class的相关数据存储在永久带PermGen(jdk1.8 则是 metaspace),永久带是全局共享的,

因此静态方法锁相当于类的一个全局锁,会锁所有调用该方法的线程;

  • 代码块锁

synchronized (this) 是对象锁,只对对象生效,spring默认单例,只有一个对象,所以生效

synchronized ( A.class ) 是类锁,锁class,所有类对象生效

synchronized (Object) 方法,是对象锁,锁实例对象, 静态方法,是类锁对于静态方法,由于此时对象还未生成,所以只能采用类锁;

锁住的是所有以该对象为锁的代码块。它有多个队列,当多个线程一起访问某个对象监视器的时候,对象监视器会将这些线程存储在不同的容器中。

使用

普通方法使用

public synchronized void m1() {

}

静态方法使用

public synchronized static void m0() {

}

代码块中使用类锁

public static void m0() {
	synchronized (A.class) {
    	
	}
}

代码块中使用对象类锁

public static void m0() {
	synchronized (this) {
    	
	}
}

代码块中使用对象锁

# 若下面对象lock 是 static 则为全局锁,若为普通对象,则锁当前

private static final Object lock = new Object();


public static void m0() {
	synchronized (lock) {

	}
}

Spring 事务

​ 日常中我们使用的spring都是用声明式事务,声明式事务由于基于AOP:将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。而Spring AOP 是构建在动态代理的基础上。

事务失效场景

下列场景会失效

  • 方法不是public类型的
  • 启用spring事务管理功能
  • 自身调用问题
  • 异常类型错误(默认回滚的是:RuntimeException)
  • 异常被吞了(catch)
  • 业务和spring事务代码必须在一个线程中
  • 数据库引擎不支持事务
  • 没有被 Spring 管理
  • 数据源没有配置事务管理器

事务类内部方法调用事务不生效问题

现象:

同一个类中 非事务A掉事务B B抛异常 A无事务 B事务不生效

原因:

事务基于aop的代理,仅有外部方法调用过程才会被代理截获,目标方法才由 Spring 生成的代理对象来管理,若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,会失效

解决方案

  • AopContext.currentProxy()
  • 拆分方法到不同的service
  • 注入自己 @Autowired

同步锁与事务配合使用

开发中,有需求为 既有同步性要求,又有事务一致性要求,应该按下面用法

把同步关键字放到controller中,

private static final Object lock = new Object();

public void t1() {
    synchronized (lock) {
        service.t2();
    }
}

service

@Transactional
public void t2() {
	//业务
}

你可能感兴趣的:(spring,java,后端)