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 {
}