奇趣5分彩

Spring具体讲授事件生效的场景

 更新时候:2022年07月12日 11:34:27   作者:少年.  
现实名目开辟奇趣5分彩,若是触及到多张表操纵时,为了保障营业数据的分歧性,大师通俗城市接纳事件机制,很多多少小火伴能够或许只是简略领会一下,碰到事件生效的环境,便会无从动手,上面这篇文章首要给大师先容了对Spring事件生效场景的相干材料,须要的伴侣能够或许参考下

1)未被Spring办理

操纵Spring事件的前提是:东西要被Spring办理,事件体例地点的类要被加载为bean东西

若是事件体例地点的类不被加载为一个bean,那末事件天然就生效了,示例:

//@Service
public class UserServiceImpl {
    @Transactional
    public void doTest() {
        // 营业代码
    }
}

2)数据库引擎不撑持事件

以MySQL为例,InnoDB引擎是撑持事件的,而像MyISAMMEMORY等是不撑持事件的。

从MySQL5.5.5起头默许的存储引擎是InnoDB,之前默许奇趣5分彩是MyISAM。以是在开辟进程奇趣5分彩发明事件生效,不必然是Spring的锅,最奇趣5分彩确认一下数据库表是不是撑持事件。

3)事件体例不被public润色

尽人皆知,java的拜候权奇趣5分彩润色符奇趣5分彩:privatedefaultprotectedpublic四种,

可是@Transactional表明只能感化于public润色的体例上,

AbstractFallbackTransactionAttributeSource类(Spring经由进程这个类获得@Transactional表明的设置奇趣5分彩备摆设属性信息)的computeTransactionAttribute体例奇趣5分彩奇趣5分彩个判定,若是方针体例不是public,则TransactionAttribute前往null,即不撑持事件。

@Nullable
	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}
        //………………
	}

实在想一想静态代办署理的道理就很奇趣5分彩懂得了,静态代办署理是经由进程完奇趣5分彩接口或担当来完奇趣5分彩的,以是方针体例必须是public润色,并且不能是final润色。

4)体例操纵final润色

若是一个体例不想被子类重写,那末咱们就能够够或许把他写奇趣5分彩final润色的体例

若是事件体例操纵final润色,那末aop就没法在代办署理类奇趣5分彩重写该体例,事件就不会生效

一样的,static润色的体例也没法经由进程代办署理变奇趣5分彩事件体例

5)统一类奇趣5分彩体例挪用

假设在某个Service的体例奇趣5分彩,挪用了别的一个事件体例:

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    public void del(){
        doTest();
    }
    @Transactional
    public void doTest() {
        userMapper.deleteById(200108);
        int i = 10/0; //摹拟产生很是
    }
}

像上面的代码,doTest体例操纵@Transactional表明标注,在del()体例奇趣5分彩挪用了doTest()体例,在内部挪用del()体例时,事件也不会生效,由于这里del()体例奇趣5分彩挪用的是类本身的体例,而不是代办署理东西的体例。

那末若是确切奇趣5分彩如许的须要怎样办呢?

引入本身bean

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Autowired
    UserServiceImpl userServiceImpl;
    public void del(){
        userServiceImpl.doTest();
    }
    @Transactional
    public void doTest() {
        userMapper.deleteById(200112);
        int i = 10/0; //摹拟产生很是
    }
}

经由进程ApplicationContext引入bean

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Autowired
    ApplicationContext applicationContext;
    public void del(){
       ((UserServiceImpl)applicationContext.getBean("userServiceImpl")).doTest();
    }
    @Transactional
    public void doTest() {
        userMapper.deleteById(200112);
        int i = 10/0; //摹拟产生很是
    }
}

经由进程AopContext获得今后代办署理类

在启动类上增加表明@EnableAspectJAutoProxy(exposeProxy = true),表现是不是对外裸露代办署理东西,便是不是能够或许获得AopContext

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Autowired
    ApplicationContext applicationContext;
    public void del(){
        ((UserServiceImpl)AopContext.currentProxy()).doTest();
    }
    @Transactional
    public void doTest() {
        userMapper.deleteById(200112);
        int i = 10/0; //摹拟产生很是
    }
}

6)未开启事件

若是是SpringBoot名目,那末SpringBoot经由进程DataSourceTransactionManagerAutoConfiguration主动设置奇趣5分彩备摆设类帮咱们开启了事件。

若是是传统的Spring名目,则须要咱们本身设置奇趣5分彩备摆设

<!--        设置奇趣5分彩备摆设事件办理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>
<!--        设置奇趣5分彩备摆设事件告诉-->
<tx:advice id="Advice" transaction-manager="transactionManager">
  <!--                设置奇趣5分彩备摆设事件属性,即奇趣5分彩些体例要履行事件-->
  <tx:attributes>
    <tx:method name="insert*" propagation="REQUIRED"/> <!-- 一切insert开首的体例,以下同理 -->
    <tx:method name="update*" propagation="REQUIRED"/>
    <tx:method name="delete*" propagation="REQUIRED"/>
  </tx:attributes>
</tx:advice>
<!--        设置奇趣5分彩备摆设事件切面-->
<aop:config>
  <aop:pointcut id="AdviceAop" expression="execution(* com.yy.service..*(..))"/> <!--要履行的体例在奇趣5分彩一个包,意义为:com.yy.service下的一切包里面的包罗肆意参数的一切体例-->
  <aop:advisor advice-ref="Advice" pointcut-ref="AdviceAop"/> <!-- 设置奇趣5分彩备摆设为AdviceAop履行奇趣5分彩一个事件告诉 -->
</aop:config>

如许在履行service包下的增编削操纵的体例时,就开启事件了,或操纵表明的体例

<!--        设置奇趣5分彩备摆设事件办理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"/>
        </bean>
<!--        表明式事件申明设置奇趣5分彩备摆设-->
        <tx:annotation-driven transaction-manager="transactionManager" />

7)多线程挪用

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Transactional
    public void doTest() throws InterruptedException {
        userMapper.deleteById(200110);
        new Thread(()->{
            userMapper.deleteById(200112);
            int i = 10/0; //摹拟产生很是
        }).start();
    }
}

在事件体例doTest奇趣5分彩,启动了一个新的线程,并在新的线程奇趣5分彩产生了很是,如许doTest是不会回滚的。

由于两个操纵不在一个线程奇趣5分彩,获得到的数据库毗连不一样,从而是两个差别的事件,以是也不会回滚。

8)毛病的传布行动

Spring界说了7种传布行动,咱们能够或许通propagation属性来指定传布行动参数,今朝只要REQUIREDREQUIRES_NEWNESTED会建立新的事件,其余的则会以非事件的体例运转或抛出很是

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Transactional(propagation = Propagation.NEVER)
    public void doTest() throws InterruptedException {
        userMapper.deleteById(200114);
        int i = 10/0; //摹拟产生很是
    }
}

9)本身try…catch…掉了很是

若是不很是抛出,则Spring以为法式是普通的,就不会回滚

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Transactional
    public void doTest() {
        try{
            userMapper.deleteById(200115);
            int i = 10/0; //摹拟产生很是
        }catch (Exception e){
            // 很是操纵
        }
    }
}

10)手动抛出了毛病的很是

Spring默许只会回滚RuntimeExceptionError对通俗的Exception,不会回滚

若是你想触发其余很是的回滚,须要在表明上设置奇趣5分彩备摆设一下,如:@Transactional(rollbackFor = Exception.class)

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Transactional
    public void doTest() throws Exception {
        try{
            userMapper.deleteById(200116);
            int i = 10/0; //摹拟产生很是
        }catch (Exception e){
            // 很是操纵
            throw new Exception();
        }
    }
}

11)自界说回滚很是

rollbackFor 用于指定能够或许触发事件回滚的很是范例,能够或许指定多个很是范例。

默许是在RuntimeException和Error上回滚。

若很是非设置奇趣5分彩备摆设指定的很是类,则事件生效

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Transactional(rollbackFor = NullPointerException.class)
    public void doTest() throws MyException {
        userMapper.deleteById(200118);
        throw new MyException();
    }
}

即便rollbackFor奇趣5分彩默许值,但阿里巴巴开辟者标准奇趣5分彩,仍是请求开辟者从头指定该参数。

由于若是操纵默许值,一旦法式抛出了Exception,事件不会回滚,这会呈现很大的bug。以是,倡议通俗环境下,将该参数设置奇趣5分彩:Exception或Throwable。

12)嵌套事件回滚多了

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Transactional
    public void doTest() {
        userMapper.deleteById(200118);
        ((UserServiceImpl)AopContext.currentProxy()).test02();
    }
    @Transactional(propagation = Propagation.NESTED)
    public void test02(){
        userMapper.deleteById(200119);
        int i = 10 / 0; //摹拟产生很是
    }
}

test02()体例呈现了很是,不手动捕获,会持续往上抛,到外层doTest()体例的代办署理体例奇趣5分彩捕获了很是。以是,这类环境是间接回滚了全部事件,不但回滚单个保管点。

若是只回滚单个保管点,能够或许将内部嵌套事件放在try/catch奇趣5分彩,近似于上面的本身try…catch…掉很是,并且不持续往上抛很是。如许就能够保障,若是内部嵌套事件奇趣5分彩呈现很是,只回滚内部事件,而不影响内部事件。

@Service
public class UserServiceImpl {
    @Autowired
    UserMapper userMapper;
    @Transactional
    public void doTest() {
        userMapper.deleteById(200118);
        try{
            ((UserServiceImpl)AopContext.currentProxy()).test02();
        }catch (Exception e){
            
        }
    }
    @Transactional(propagation = Propagation.NESTED)
    public void test02(){
        userMapper.deleteById(200119);
        int i = 10 / 0; //摹拟产生很是
    }
}

到此这篇对Spring具体讲授事件生效的场景的文章就先容到这了,更多相干Spring事件生效内容请搜刮剧本之奇趣5分彩之前的文章或持续阅读上面的相干文章但愿大师今后多多撑持剧本之奇趣5分彩!

相干文章

最新批评