zoukankan      html  css  js  c++  java
  • spring 注解学习 六 声明式事务

    六、spring注解版学习 声明式事务

    6.1、spring事务的使用

    1、引入事务的包

    <dependencies>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-context</artifactId>
    			<version>${spring-version}</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-aspects</artifactId>
    			<version>${spring-version}</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-jdbc</artifactId>
    			<version>${spring-version}</version>
    		</dependency>
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>${junit-version}</version>
    			<scope>test</scope>
    		</dependency>
    		<dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.16</version>
            </dependency>
    		<dependency>
    			<groupId>com.mchange</groupId>
    			<artifactId>c3p0</artifactId>
    			<version>0.9.5.2</version>
    		</dependency>
    	</dependencies>
    

    2、配置数据源

    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url_01=jdbc:mysql://localhost:3306/rbac?useSSL=true
    jdbc.url_02=jdbc:mysql://localhost:3306/project_crowd?useSSL=true
    jdbc.username=root
    jdbc.password=123456
    

    3、配置类

    import javax.sql.DataSource;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    @Configuration
    @EnableTransactionManagement//开始注解版事务
    @PropertySource(value= {"classpath:/application.properties"})
    public class TxConfig {
    
        @Value("${jdbc.username}")
        private String user;
        
        @Value("${jdbc.password}")
        private String password;
        
        @Value("${jdbc.driver}")
        private String driver;
        
        @Value("${jdbc.url_01}")
        private String url;
        /**
         * 注册数据源
         * @return
         * @throws PropertyVetoException
         */
        @Bean
        public DataSource dataSource() throws PropertyVetoException {
            ComboPooledDataSource dataSource=new ComboPooledDataSource();
            dataSource.setUser(user);
            dataSource.setPassword(password);
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            return dataSource;
        }
        /**
         * 注册事务管理器
         * @return
         * @throws PropertyVetoException
         */
        @Bean
        public PlatformTransactionManager transactionManager() throws PropertyVetoException {
            DataSourceTransactionManager transactionManager=new DataSourceTransactionManager(dataSource());
            return transactionManager;
        }
        
        @Bean
        public JdbcTemplate jdbcTemplate(DataSource dataSource) {
            JdbcTemplate jdbcTemplate=new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
    }
    

    3、业务代码使用

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class UserService {
        
        @Autowired
        private UserDao userDao;
        
        @Transactional
        public void insertService() {
            userDao.insert();
            int i=1/0;
        }
    
    }
    
    @Repository
    public class UserDao {
        
        @Autowired
        private JdbcTemplate jdbcTemplate;
        
        
        public void insert() {
            String sql="insert into t_role(name) values(?)";
             String uuid=UUID.randomUUID().toString().substring(0,5);
            jdbcTemplate.update(sql, uuid);
        }
    
    }
    

    6.2、声明式事务的使用与失效情况

    package org.springframework.transaction.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.springframework.core.annotation.AliasFor;
    import org.springframework.transaction.TransactionDefinition;
    
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Transactional {
    
    	@AliasFor("transactionManager")
    	String value() default "";
    
    	
    	@AliasFor("value")
    	String transactionManager() default "";
    
    	//用于配置事务的传播机制
    /*该属性用于设置事务的传播行为 
    例如:@Transactional(propagation=Propagation.NOT_SUPPORTED) 
    事物传播行为介绍:
    @Transactional(propagation=Propagation.REQUIRED) 如果有事务, 那么加入事务, 没有的话新建一个(默认) @Transactional(propagation=Propagation.NOT_SUPPORTED) 容器不为这个方法开启事务 @Transactional(propagation=Propagation.REQUIRES_NEW) 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务 
    @Transactional(propagation=Propagation.MANDATORY) 必须在一个已有的事务中执行,否则抛出异常 @Transactional(propagation=Propagation.NEVER) 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反) @Transactional(propagation=Propagation.SUPPORTS) 如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务
    */
    
    	Propagation propagation() default Propagation.REQUIRED;
    
    	//用于配置事务的隔离级别
    	Isolation isolation() default Isolation.DEFAULT;
    
    	//该属性用于设置事务的超时秒数,默认值为-1表示永不超时
    	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
    
    	//该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false
    	boolean readOnly() default false;
    /**
    该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如: 
    指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)
    指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, BusnessException.class})
    
    */
    	Class<? extends Throwable>[] rollbackFor() default {};
    
    	
    	String[] rollbackForClassName() default {};
    
    	
    	Class<? extends Throwable>[] noRollbackFor() default {};
    
    	
    	String[] noRollbackForClassName() default {};
    
    }
    

    6.3、声明式事务常见的失效情况

    1、事务的传播机制配置错误

    2、Spring默认情况下会对(RuntimeException)及其子类来进行回滚,在遇见Exception及其子类的时候则不会进行回滚操作。

    可采用rollbackFor属性来配置遇到什么异常时回滚

       @Transactional(rollbackFor = Throwable.class)
    

    3、 @Transactional既可以作用于接口,接口方法上以及类的方法上。但是Spring官方不建议接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。 Spring默认使用的是jdk自带的基于接口的代理,而没有使用基于类的代理CGLIB。
    4、 @Transactional注解底层使用的是动态代理来进行实现的,如果一个没有@Transactional的方法调用同一个类中的带@Transactional注解的方法,则事务不起作用。原因时声明式事务是基于动态代理的,同一个类中的示例方法的相互调用是通过this对象调用的,没有走代理对象,因此事务的代码无法执行

    `@Target({ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Transactional(value="transactionManager",propagation = Propagation.REQUIRED,rollbackFor = java.lang.Throwable.class,isolation = Isolation.READ_COMMITTED)
    public @interface DefaultTransactional {

    }
    `

  • 相关阅读:
    说一下 session 的工作原理?
    说一下 JSP 的 4 种作用域?
    MVC的各个部分都有那些技术来实现?如何实现?
    window.onload()函数和jQuery中的document.ready()有什么区别?
    JQuery有几种选择器?
    jQuery 库中的 $() 是什么?
    按照锁的粒度分数据库锁有哪些?锁机制与InnoDB锁算法?
    隔离级别与锁的关系?
    Java语言基础(二)之数据类型转换、运算符、方法入门
    Java语言基础(一)
  • 原文地址:https://www.cnblogs.com/cplinux/p/14589173.html
Copyright © 2011-2022 走看看