spring 注解学习 六 声明式事务

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

6.1、spring事务的使用

1、引入事务的包



org.springframework
spring-context
${spring-version}


org.springframework
spring-aspects
${spring-version}


org.springframework
spring-jdbc
${spring-version}


junit
junit
${junit-version}
test


mysql
mysql-connector-java
8.0.16


com.mchange
c3p0
0.9.5.2

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  阅读(113)  评论(0)    收藏  举报