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 {

}

posted @ 2021-03-28 17:07  阿瞒123  阅读(75)  评论(0编辑  收藏  举报