精华内容
下载资源
问答
  • sevice层的一个事务方法A(), 在A()方法里面调用了spring框架中某个类的一个方法B(), 问题是,方法B()会加入到A...还有就是这些与spring的事务的传播属性有没有关系? 希望有大神能够从spring的原理去解释。
  • 最近在项目中遇到一个问题,在service类中调用当前类的一个方法没有开启事务,如下: @Service("userService") public class UserServiceImpl implements UserService{ @Autowired private UserMapper ...

    最近在项目中遇到一个问题,在service类中调用当前类的一个方法,没有开启事务,如下:

    @Service("userService")
    public class UserServiceImpl implements UserService{
    	
    	@Autowired
    	private UserMapper userMapper;	
    
    	//默认情况下Spring的声明式事务对所有的运行时异常进行回滚	
    	@Transactional
    	@Override
    	public void addUser() {
    		User user1 = new User();
    		user1.setUserName("zhaoliu21");
    		user1.setName("赵柳21");
    		user1.setPassword("12323");
    		userMapper.insert(user1);				
    		this.updateUser(user1);  //this.updateUser()调用的并不是spring的代理对象,所以没有事务		
    	}
    
    	@Transactional(propagation=Propagation.REQUIRES_NEW)
    	@Override
    	public void updateUser(User user) {
    		System.out.println("************updateUser  开始**************");
    		User user1 = new User();
    		user1.setId(46L);
    		user1.setName("王武");
    		userMapper.updateUserById(user1);
    		System.out.println("************updateUser  结束**************");
    	}
    
    }
    

    如上代码,在addUser()中调用this.updateUser()时,由于updateUser()上配置了事务传播属性Propagation.REQUIRES_NEW,表示重新开启一个新事务,但是我们在执行后,通过日志发现却没有开启新事务。
    原因是Spring的事务是通过aop管理的,基于aop生成代理对象开启事务。所以在同一个类中直接调用方法,并没有使用到代理对象。

    解决方法有三种,如下:
    1.在service类中注入自己本身,然后调用该类方法:

    @Service("userService")
    public class UserServiceImpl implements UserService{
    		
    	@Autowired
    	private UserMapper userMapper;
    	@Autowired
    	private UserService userService;
    	
    	//默认情况下Spring的声明式事务对所有的运行时异常进行回滚
    	@Transactional
    	@Override
    	public void addUser() {
    		User user1 = new User();
    		user1.setUserName("zhaoliu21");
    		user1.setName("赵柳21");
    		user1.setPassword("12323");
    		user1.setSex(1);
    		userMapper.insert(user1);
    		userService.updateUser(user1);
    	}
    
    	@Transactional(propagation=Propagation.REQUIRES_NEW)
    	@Override
    	public void updateUser(User user) {	
    		System.out.println("************updateUser  开始**************");
    		User user1 = new User();
    		user1.setId(46L);
    		user1.setName("王武");
    		userMapper.updateUserById(user1);
    		System.out.println("************updateUser  结束**************");
    	}
    }
    

    2.若是Springboot工程,则可以用注解开启cglib代理,开启exposeProxy=true,暴露代理对象

    @EnableAspectJAutoProxy(exposeProxy=true)
    @SpringBootApplication
    @EnableTransactionManagement
    @MapperScan("com.bms.mapper")
    public class Application {
    	public static void main(String[] args) {
    		ApplicationContext ac = SpringApplication.run(Application.class, args);
    	}
    }
    

    或是用XML配置文件配置:

    <aop:aspectj-autoproxy expose-proxy="true"/>
    

    这样就可以在代码中调用了:

    @Service("userService")
    public class UserServiceImpl implements UserService{
    		
    	@Autowired
    	private UserMapper userMapper;
    	
    	//默认情况下Spring的声明式事务对所有的运行时异常进行回滚
    	@Transactional
    	@Override
    	public void addUser() {
    		User user1 = new User();
    		user1.setUserName("zhaoliu21");
    		user1.setName("赵柳21");
    		user1.setPassword("12323");
    		user1.setSex(1);
    		userMapper.insert(user1);
    		((UserService)AopContext.currentProxy()).updateUser(user1);
    	}
    
    	@Transactional(propagation=Propagation.REQUIRES_NEW)
    	@Override
    	public void updateUser(User user) {	
    		System.out.println("************updateUser  开始**************");
    		User user1 = new User();
    		user1.setId(46L);
    		user1.setName("王武");
    		userMapper.updateUserById(user1);
    		System.out.println("************updateUser  结束**************");
    	}
    }
    

    3.通过代码获取spring容器中的bean,然后调用:

    @Component
    public class SpringContextHolder implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            SpringContextHolder.applicationContext = applicationContext;
        }
    
        public static ApplicationContext getApplicationContext() {
            assertApplicationContext();
            return applicationContext;
        }
    
        @SuppressWarnings("unchecked")
        public static <T> T getBean(String beanName) {
            assertApplicationContext();
            return (T) applicationContext.getBean(beanName);
        }
    
        public static <T> T getBean(Class<T> requiredType) {
            assertApplicationContext();
            return applicationContext.getBean(requiredType);
        }
    
        private static void assertApplicationContext() {
            if (SpringContextHolder.applicationContext == null) {
                throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");
            }
        }
    
    }
    
    @Service("userService")
    public class UserServiceImpl implements UserService{
    		
    	@Autowired
    	private UserMapper userMapper;
    	
    	//默认情况下Spring的声明式事务对所有的运行时异常进行回滚
    	@Transactional
    	@Override
    	public void addUser() {
    		User user1 = new User();
    		user1.setUserName("zhaoliu21");
    		user1.setName("赵柳21");
    		user1.setPassword("12323");
    		user1.setSex(1);
    		userMapper.insert(user1);
    		SpringContextHolder.getBean(UserService.class).updateUser(user1);
    	}
    
    	@Transactional(propagation=Propagation.REQUIRES_NEW)
    	@Override
    	public void updateUser(User user) {	
    		System.out.println("************updateUser  开始**************");
    		User user1 = new User();
    		user1.setId(46L);
    		user1.setName("王武");
    		userMapper.updateUserById(user1);
    		System.out.println("************updateUser  结束**************");
    	}
    }
    

    阿里云拼团2折起:https://www.aliyun.com/acts/hi-group-buying?userCode=litzwg4e
    最高2000代金券:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=litzwg4e

    展开全文
  • PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY -- 支持...

    首先我们来看下spring事务的传播机制及原因分析;

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

    spring默认的是PROPAGATION_REQUIRED机制,如果方法A标注了注解@Transactional 是完全没问题的,执行的时候传播给方法B,因为方法A开启了事务,线程内的connection的属性autoCommit=false,并且执行到方法B时,事务传播依然是生效的,得到的还是方法A的connection,autoCommit还是为false,所以事务生效;反之,如果方法A没有注解@Transactional 时,是不受事务管理的,autoCommit=true,那么传播给方法B的也为true,执行完自动提交,即使B标注了@Transactional ;

    在一个Service内部,事务方法之间的嵌套调用,普通方法和事务方法之间的嵌套调用,都不会开启新的事务.是因为spring采用动态代理机制来实现事务控制,而动态代理最终都是要调用原始对象的,而原始对象在去调用方法时,是不会再触发代理了!

    所以以上就是为什么我在没有标注事务注解方法A里去调用标注有事务注解方法B而没有事务滚回的原因;

     

    看到这里,有的看官可能在想,你在方法A上标个注解不就完了吗?为什么非要标注在方法B上?

    由于我这里是循环更新数据,调用一次方法B就更新一次数据,涉及到几张表,需要执行几条update sql, 一条数据更新失败不影响所有数据,所以说一条数据更新执行完毕后就提交一次事务,如果标注在方法A上,要所有的都执行完毕了才提交事务,这样子是有问题滴.

    下边先上下代码:

    方法A:无事务控制

    方法B:有事务控制

    方法B处理失败手动抛出异常触发回滚:

    方法A调用方法B:

    从上图可以看到,如果方法B中User更新出错后需要回滚RedPacket数据,所以User更新失败就抛出了继承自RuntimeException的自定义异常,并且在调用方把这个异常catch到重新抛出,触发事务回滚,但是并没有执行;

    下面是解决方案:

       1.把方法B抽离到另外一个XXService中去,并且在这个Service中注入XXService,使用XXService调用方法B;

          显然,这种方式一点也不优雅,且要产生很多冗余文件,看起来很烦,实际开发中也几乎没人这么做吧?.反正我不建议采用此方案;

       2.通过在方法内部获得当前类代理对象的方式,通过代理对象调用方法B

       上面说了:动态代理最终都是要调用原始对象的,而原始对象在去调用方法时,是不会再触发代理了!

        所以我们就使用代理对象来调用,就会触发事务;

    综上解决方案,我觉得第二种方式简直方便到炸. 那怎么获取代理对象呢? 这里提供两种方式:

       1.使用 ApplicationContext 上下文对象获取该对象;

       2.使用 AopContext.currentProxy() 获取代理对象,但是需要配置exposeProxy=true

    我这里使用的是第二种解决方案,具体操作如下:

    springboot启动类加上注解:@EnableAspectJAutoProxy(exposeProxy = true)

    方法内部获取代理对象调用方法

    完了后再测试,数据顺利回滚,至此,问题得到解决!

     

     

    -----------------------------------------------------------------------------------------------------------

    附加:

    配置expose-proxy="true"

    <aop:aspectj-autoproxy expose-proxy="true"/>
    @RestController
    @RequestMapping(value = "ztest")
    public class Ztest implements ServletConfigAware, ServletContextAware {
    
        private ServletContext servletContext;
        private ServletConfig servletConfig;
    
        @Resource
        private t t;
    
        @Override
        public void setServletConfig(ServletConfig servletConfig) {
            this.servletConfig = servletConfig;
        }
    
        @Override
        public void setServletContext(ServletContext servletContext) {
            this.servletContext = servletContext;
        }
    
        /**
         * 测试方法
         *
         * @param request
         * @return
         */
        @RequestMapping("/test")
        public JsonResult test(HttpServletRequest request, @RequestParam Map paramMap) {
            try {
                t.t1(request);
            }catch (Exception ex){
                ex.printStackTrace();
            }
            return null;
        }
    }
    
    
    @Service
    class t{
        @Transactional
        public void t1(HttpServletRequest request) throws Exception {
            ServletContext sc1 = ContextLoader.getCurrentWebApplicationContext().getServletContext();
            ServletContext sc2 = request.getServletContext();
            //ServletContext sc = servletConfig.getServletContext();
    
            System.out.println(sc1 == sc2);
            WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(sc1);
    
            t currentProxy = (t)AopContext.currentProxy();
            System.out.println(currentProxy.getClass());//t的代理对象
    
            t ztestService = (t)applicationContext.getBean("ztestService");
            System.out.println(ztestService.getClass());//t的代理对象
    
            System.out.println(this.getClass());//t的真实对象
        }
    }
    

     

     

    展开全文
  • Spring 事务传播

    2021-03-11 00:12:32
    1. Spring支持注解形式的事务控制 @Transactional 默认 propagation = Propagation.REQUIRED 事务传播 - Propagation value description ... 支持已存在的事务,当前方法没有事务不会新创建事务 .

    1. Spring 支持注解形式的事务控制 @Transactional 默认 propagation = Propagation.REQUIRED

    事务传播 - Propagation
    value description

    REQUIRED

    当前方法必须被事务控制(包裹),如果当前方法已经被存在于一个事务中,则什么都不做,如果当前方法没有被事务控制(包裹)则新创建一个事务。

    SUPPORTS

    支持已存在的事务,当前方法没有事务不会新创建事务
    MANDATORY 支持一个当前事务(必须存在),如果当前不存在事务则抛出异常
    REQUIRES_NEW 创建一个新事务,挂起已存在的事务,不受外层事务影响,但会影响外层事务!(内层事务回滚,外层事务也会回滚)
    NOT_SUPPORTED 执行时不进行事务控制,如果当前存在事务,则挂起当前事务,不影响外层事务!
    NEVER 执行时不进行事务控制,如果当前存在事务则抛出异常
    NESTED 如果当前存在事务,则创建一个子事务,受外层事务影响,否则则等同于 REQUIRED 

     

    展开全文
  • PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。PROPAGATION_MANDATORY--支持当前事务,...

    一.原有事务传播性的方法

         原来记事务传播性的时候,是死记硬背7种,每次背了就忘背了就忘

    PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。


    PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
     

    PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
     

    PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
     

    PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
     

    PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

     

    PROPAGATION_NESTED--嵌套到父事务中,跟着父事务提交而提交,跟着父事务回归而回滚

     

    二. 最好记忆法

    SpringAPI设计的非常不错,基本知道英文翻译就能知道作用。

    required:必须的 说明事务时必须的 没有就新建事务

    supports::支持  说明仅仅支持事务 没有事务就以非事务方法执行

    mandatory:强制的, 说明一定要有事务,没有事务就抛异常

    reuquires_new 必须新建事务,当前有事务,就将事务挂起

    not_supported: 不支持事务,如果存在事务就挂起

    never:绝不会有是u我 如果存在事务就抛出异常

    nested:嵌套,当前有事务,新建一个事务嵌套到父事务中,父事务回归,新建的事务也会回滚

    看看上面的方法,只用记住 required(必须的) ,supports(支持),mandatory(强制的), never(绝不会),nested(嵌套)五个简单的单词,再去联想7种情况 那么事务的传播性记住就相对很容易啦。

    展开全文
  • 前言 Spring 提供了事务的管理机制,我们只需要在方法或者类上加上 @Transactional 注解进行事务管理。而非事务方法与事务方法之间相互调用,有时会使事务失效,...支持当前事务,如果当前没有事务,就新建一个事务。 P
  • Spring事务的一些学习

    2020-10-23 10:28:32
    如果当前方法没有事务,则就新建一个事务;如果已经存在一个事务中,就加入到这个事务中。此类型是最常见的默认选择。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚) Propagation_Supports 表示被...
  • 前段时间,朋友问了我一个问题,说有一个service类中,有一个A()方法和B()方法, A()方法没有添加... PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务,最常见的选择。 PROPAGATION_SUPPORT
  • 最近遇到一个很棘手的问题,至今也解释不清楚原因,不过已经找到了解决方案。...当前方法必须在已经定义的Transaction中运行,如果没有已定义的Transaction则抛出异常。 Propagation.NEST。如果没有已定义的Tran
  • Spring事务控制放在service层,在service方法中一个方法调用service中的另一个方法,...如果当前没有事务,则新建一个新的事务。因此只开启了一个事务。 Spring事务的传播行为的7种类型 TransactionDefinition.PROP...
  • 前段时间,朋友问了我一个问题,说有一个service类中,有一个A()和B(), A()没有添加事务,B() 添加了一个默认的事务,那么如果B()抛出...PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行.
  • 是Spring在当前线程内,处理多个数据库操作方法事务时所做的一种事务应用策略。事务本身并不存在什么传播特性,不要混淆事务本身和Spring的事务应用策略。(当然,找工作面试时,还是可以巧妙的描述传播特性的)2、一...
  • 事务

    2019-12-04 20:22:26
    * REQUIRED: 使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法是必须运行在一个事务中的; * 如果当前存在事务,则加入这个事务,成为一个整体。 * 举例:领导没饭吃,我有钱,我会自己买了自己吃...
  • 在我的Spring MVC Web应用程序中尝试调用“persist”方法将实体模型保存到数据库时,我收到此错误.不能真正找到互联网上可能涉及到这个特定错误的任何帖子或页面. EntityManagerFactory bean似乎是错误的,但是我对...
  • 事务时间(Sysdate)不对的解决方法

    千次阅读 2012-04-06 15:35:03
    做库存事务,发现Transaction Date是...但查了下Unix Server的时间没有问题,是当前时间 -bash-3.2$ date Sun Mar 4 23:25:45 PST 2012 解决方法: 先设定一个固定的时间到系统 SQL> alter system set fixed_date
  • 前边的话当前SpringCloud作为微服务开发的首选开源方案提供了完善的微服务开发技术套件,不过针对分布式领域的难题–分布式事务控制并没有成熟的方案,本篇将介绍作为柔性事务控制的优秀方案RocketMQ的使用原理和...
  • 事务传播性

    2019-02-15 11:21:04
    1、propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。 2、propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。 3、...
  • propagation属性的传播行为:REQUIRED:指定当前方法必需在事务环境中运行,如果当前有事务环境就加入当前正在执行的事务环境,如果当前没有事务,就新建一个事务。这是默认值。SUPPORTS:指定当前方法加入当前事务...
  • spring 事务

    2019-10-25 13:48:13
    1、事务基本特性(1)、原子性(2)、隔离性(3)、持久性(4)、一致性 2、事务分类:编程式事务,声明式事务。 3、事务的传播行为: PROPAGATION_REQUIRED—如果当前有事务...//如果外层方法没有事务,就会以非...
  • 开发需求 在OAF的开发中,可能有这样的需求,在选择保存按钮时,如果存在改动的数据,则提交事务,保存到数据库中;...此方法用于判断当前事务中,视图对象是否发生过变更。但是此方法只对基于实体
  • spring事务相关

    2020-12-15 09:54:23
    REQUIRED: 使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法是必须运行在一个事务中的; 如果当前存在事务,则加入这个事务,成为一个整体。 举例:领导没饭吃,我有钱,我会自己买了自己
  • 一Propagation (事务的传播属性) Propagation key属性确定代理应该给哪个方法增加事务行为这样的属性最重要的部份是传播行为有以下选项可供使用PROPAGATION_REQUIRED--支持当前事务如果当前没有事务就新建一个事务这...
  • 在做一个定时执行job的时候(非web项目),发现配置的事务没有起作用,大佬指点说是因为session没有当前线程绑定。似懂非懂,查了好多资料,自己又一点一点测试,发现以下两种方法。仅供参考,...
  • 如果当前没有事务,则创建一个新的事务。==> 会跟随service层方法回滚事务SUPPORTS :如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。==> 会跟随service层方法回滚事务...
  • Spring事务

    2018-09-18 15:34:20
    propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是Spring默认的选择。 propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法...
  • 是Spring在当前线程内,处理多个数据库操作方法事务时所做的一种事务应用策略。事务本身并不存在什么传播特性,不要混淆事务本身和Spring的事务应用策略。(当然,找工作面试时,还是可以巧妙的描述传播特性的)一说到...
  • 如题:在1调用当前子系统时,可以用spring的transactional注解来实现,但 当我使用chix报文调用其它子系统实现对数据的注销,领取以及复核时,事务没有起到作用,那么我如何实现在领取数据有异常的情况下,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,119
精华内容 447
关键字:

当前方法没有事务