• tx


    一、编程式事务辅助类

    @Component
    public class TxHelper {
    
        @Autowired
        private PlatformTransactionManager tx;
    
        public TransactionStatus start() {
            DefaultTransactionDefinition txDef = new DefaultTransactionDefinition();
            return tx.getTransaction(txDef);
        }
    
        public void commit(TransactionStatus txStatus) {
            tx.commit(txStatus);
        }
    
        public void rollback(TransactionStatus txStatus) {
            tx.rollback(txStatus);
        }
    }

    注解异常catch中手动回滚

    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

    <=>

    @Autowired
    private PlatformTransactionManager tx;
    DefaultTransactionDefinition txDef = new DefaultTransactionDefinition();
    TransactionStatus txStatus = tx.getTransaction(txDef);
    tx.rollback(txStatus);

    二、springboot jpa @Transactional

    1.controller

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping(path = "test")
    public class FacadeController {
    
        @Autowired
        private FruitService fruitService;
        @Autowired
        private FacadeService facadeService;
        @Autowired
        private PlatformTransactionManager tx;
    
    
        @RequestMapping(value = "testinit")
        public String test(String a) {
    
            return (tx==null) + "";
        }
    
        @RequestMapping(value = "add")
        public String addFruit(Fruit fruit) {
    
            Fruit result = fruitService.addFruit(fruit);
            return "SUCCESS";
        }
    
        @RequestMapping(value = "update")
        public String updateFruitPrice(Fruit fruit) {
    
            fruitService.updateFruitPrice(fruit);
            return "SUCCESS";
        }
    
        @RequestMapping(value = "updateThread")
        public String updateFruitPriceThread(Fruit fruit) {
    
            facadeService.updateFruitPrice(fruit);
            return "SUCCESS";
        }
    }

    2.实体类entity

    import lombok.Data;
    
    import javax.persistence.*;
    import java.math.BigDecimal;
    
    
    @Data
    @Entity
    @Table(name = "zz_test")
    public class Fruit {
    
    
        @Id
        @Column(name = "uid")
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(name = "name", unique = true, columnDefinition = "VARCHAR(32) DEFAULT NULL COMMENT 'fruit name'")
        private String fruitName;
    
        @Column(columnDefinition = "VARCHAR(32) DEFAULT NULL COMMENT 'fruit color'")
        private String color;
    
        @Column(nullable = false, columnDefinition = "decimal(20,4) DEFAULT 0 COMMENT 'fruit price'")
        private BigDecimal price;
    
        @Column(columnDefinition = "tinyint(2) default 0 COMMENT '价格是否超过10元'")
        private Boolean moreThan10;
    }

    3.dao层

    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    import org.springframework.data.jpa.repository.Modifying;
    import org.springframework.data.jpa.repository.Query;
    import org.springframework.stereotype.Repository;
    
    import java.math.BigDecimal;
    
    @Repository
    public interface FruitDao extends JpaRepository<Fruit, Long>, JpaSpecificationExecutor<Fruit> {
    
    
        @Modifying
        @Query(value = "update Fruit f set f.price = ?2 where f.id = ?1")
        void updatePrice(Long id, BigDecimal price);
    
        @Modifying
        @Query(value = "update Fruit f set f.moreThan10 = 1 where f.id = ?1")
        void updateFlag(Long id);
    }

    4. service接口层

    public interface FacadeService {
    
    
        void updateFruitPrice(Fruit fruit);
    }
    public interface FruitService {
    
    
        void updateFruitPrice(Long id, BigDecimal price);
    
        /**
         * 自身开启事务,调用默认级别事务方法保存
         * @param fruit
         * @return
         */
        Fruit addFruit(Fruit fruit);
    
        /**
         * 使用自身事务
         * @param fruit
         * @param selfTx
         * @return
         */
        Fruit addFruit(Fruit fruit, Boolean selfTx);
    
        void updateFruitPrice(Fruit fruit);
    
        void updateFlag(Fruit fruit);
    
        void updateFlagOtherClz(Fruit fruit);
    }

    5.实现层

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.math.BigDecimal;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    
    @Slf4j
    @Service
    public class FacadeServiceImpl implements FacadeService {
    
    
        @Autowired
        private FruitDao fruitDao;
        @Autowired
        private FruitService fruitService;
    
    
        public static final ExecutorService pool = Executors.newFixedThreadPool(2);
    
        @Override
        @Transactional(rollbackFor = Throwable.class)
        public void updateFruitPrice(Fruit fruit) {
    
    
            fruitService.updateFruitPrice(fruit);
    
            //模拟:数据必须正常记录,不相关的异常不能影响数据记录。
            try {
                /* 本类中调用, 事务不开启,多线程异步处理,不受本方法事务管理*/
                updateFlagThisClz(fruit);
    
                /* 注解经过aop切面, 事务正常开启,多线程异步处理,标识受到事务管理,回滚不更新,只更新价格 */
                //fruitService.updateFlagOtherClz(fruit);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //多线程模拟。数据更新后,需要去更新对应的业务数据表,然后再更新本表中的某字段。(如此中的价格标识字段)
        @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW)
        public void updateFlagThisClz(final Fruit fruit) {
    
            pool.execute(() -> {
    
                final BigDecimal price = fruit.getPrice();
                if(price != null && price.compareTo(BigDecimal.TEN) > 0) {
                    log.info("价格超过10元,更新标识");
    
    
                    /*
                    直接调用dao层,没有事务
                    * Exception in thread "pool-1-thread-3" org.springframework.dao.InvalidDataAccessApiUsageException:
                    * Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException:
                    * Executing an update/delete query
                    * */
                    fruitDao.updateFlag(fruit.getId());
    
    
                    //-----------------------------------------------------------------
                    /* 可以成功更新标识,多线程异步处理时,不受本类调用事务的管理 使用的是下面方法调用的事务,调用方法之后的异常不对事务生效 */
    //                fruitService.updateFlag(fruit);
    //                int temp = 1/0;
                    //-----------------------------------------------------------------
    
                }
            });
        }
    }
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.TransactionDefinition;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.transaction.support.DefaultTransactionDefinition;
    import org.springframework.transaction.support.TransactionTemplate;
    
    import java.math.BigDecimal;
    
    @Slf4j
    @Service
    public class FruitServiceImpl implements FruitService {
    
        @Autowired
        private FruitDao fruitDao;
        @Autowired
        private PlatformTransactionManager tx;
        @Autowired
        private TransactionTemplate template;
    
    
        @Override
        @Transactional
        public Fruit addFruit(Fruit fruit, Boolean selfTx) {
            Fruit data = fruitDao.save(fruit);
            return data;
        }
    
    
        /**
         * 同一个类中调用其他的事务方法,不论是否要求开启新的事务,都默认加入当前事务。如果当前方法没有事务,则没有事务启用。
         * reason: 同一个类中调用没有经过代理,事务注解没有切入点切入,无法开启事务
         * @param fruit
         * @return
         */
        @Override
        @Transactional(rollbackFor = Throwable.class)
        public Fruit addFruit(Fruit fruit) {
            Fruit data = saveData(fruit);
            int temp = 1/0; //1.调用本类方法事务没有开启。2.经过切面开启事务后,如果没有新建事务需求,加入本方法事务。皆可正常回滚
            return data;
        }
        /*
        addFruit 没有事务时(注释://@Transactional(rollbackFor = Throwable.class))
        同一个类中调用没有经过代理,事务注解没有切入点切入,无法开启事务
        @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW)
        public Fruit saveData(Fruit fruit) {
            Fruit po = fruitDao.save(fruit);
            int a = 1/0; //抛异常之前数据已保存。异常后不会回滚
            return po;
        }
        * */
    
        @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW)
        public Fruit saveData(Fruit fruit) {
            Fruit po = fruitDao.save(fruit);
            return po;
        }
    
    
        /**
         * 编程式事务。
         * 同一个类中调用,手动开启事务。
         */
        public Fruit saveData(Fruit fruit, Boolean manualTx) {
    
            DefaultTransactionDefinition txDef = new DefaultTransactionDefinition();
            txDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);//(Propagation.REQUIRES_NEW.value());
            TransactionStatus ts = tx.getTransaction(txDef);
    
            Fruit po = null;
            try {
                po = fruitDao.save(fruit);
                int a = 1/0;
                tx.commit(ts);
    
            } catch (Exception e) {
                e.printStackTrace();
                tx.rollback(ts);
            }
    
            //=========================TransactionTemplate 方式=========================
            /*Fruit po2 = template.execute(new TransactionCallback<Fruit>() {
                @Override
                public Fruit doInTransaction(TransactionStatus ts) {
    
                    try {
                        return fruitDao.save(fruit);
                    } catch (Exception e) {
                        e.printStackTrace();
                        ts.setRollbackOnly(); //设置回滚
                        throw e;
                    }
                }
            });*/
            return po;
        }
    
    
        @Override
        @Transactional
        public void updateFruitPrice(Long id, BigDecimal price) {
            fruitDao.updatePrice(id, price);
        }
    
    
    
    
        @Override
        public void updateFruitPrice(Fruit fruit) {
    
            updateFruitPrice(fruit.getId(), fruit.getPrice());
        }
    
    
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void updateFlag(Fruit fruit) {
            fruitDao.updateFlag(fruit.getId());
        }
    
    
        @Override
        @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
        public void updateFlagOtherClz(final Fruit fruit) {
    
            FacadeServiceImpl.pool.execute(() -> {
    
                final BigDecimal price = fruit.getPrice();
                if(price != null && price.compareTo(BigDecimal.TEN) > 0) {
                    log.info("价格超过10元,更新标识");
    
                    updateFlag(fruit);
                    int temp = 1/0;
                }
            });
        }
    }

    三、transaction

    PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
    PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
    PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
    PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
    PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
    PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

     

    同一个类中调用,事务失效的解决方式:

    声明式事务:强行经过代理

    1:将事务方法分离到其他类中。

    2:获取本对象的代理对象,再进行调用。具体操作如:

    1):Spring-content.xml上下文中,增加配置:<aop:aspectj-autoproxy expose-proxy="true"/>

      在xxxServiceImpl中,用(xxxService)(AopContext.currentProxy()),获取到xxxService的代理类,再调用事务方法,强行经过代理类,激活事务切面。

    2): spring boot启动类上添加注解 @EnableAspectJAutoProxy(exposeProxy = true) 开启暴露代理类对象

      AopContext.currentProxy()

    3:注入自身,然后在用注入的bean调用自己的方法也可以

    4:事务超时失效,如I/O造成的耗时,将与事务无关的操作变为线程异步执行。

    5:使用编程式事务

     

    Spring事务详细解释,满满的都是干货!

     

     Spring事务管理(详解+实例)

    https://www.cnblogs.com/wuer888/p/7840023.html

    https://www.cnblogs.com/yixianyixian/p/8372832.html

     

    Spring_第五章【Spring的事务代码实现】

    深入理解 Spring 事务原理

    @Transactional失效原因分析

    事务注解Transactional在同一个类中调用的失效问题

     

     

     

  • 相关阅读:
    jquery面试(2)
    jquery面试题
    javascript面试题(2)
    javascript--面试题
    遇到的问题:
    artTemplate的使用案列
    CSS3 background-size 属性
    listandset实例
    testng.xml
    sts设置Code Templates
  • 原文地址:https://www.cnblogs.com/foolash/p/12165254.html
Copyright © 2020-2023  润新知