Spring事物注解
1、事物注解方式: @Transactional,当标于类前时, 标识类中所有方法都进行事物处理
2、当类中某些方法不需要事物时,在该方法上添加:@Transactional
(propagation =Propagation.NOT_SUPPORTED)
3、事物传播行为介绍:
@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没有声明事务,那就不用事务.
4、事物超时设置: @Transactional(timeout=30) //默认是30秒
5、事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE):串行化
MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED
脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据
6、@Transactional注解中常用参数说明
参数名称 |
功能描述 |
readOnly |
该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true) |
rollbackFor |
该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如: 指定单一异常类:@Transactional(rollbackFor=RuntimeException.class) 指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class}) |
rollbackForClassName |
该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如: 指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException") 指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"}) |
noRollbackFor |
该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如: 指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class) 指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class}) |
noRollbackForClassName |
该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如: 指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException") 指定多个异常类名称: @Transactional(noRollbackForClassName={"RuntimeException","Exception"}) |
propagation |
该属性用于设置事务的传播行为,具体取值可参考表6-7。 例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true) |
isolation |
该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置 |
timeout |
该属性用于设置事务的超时秒数,默认值为-1表示永不超时 |
7、注意:
1、@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
2、用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception("注释");)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
如下:
1
2
3
4
5
6
7
8
|
@Transactional (rollbackFor=Exception. class ) //指定回滚,遇到异常Exception时回滚
public void methodName() {
throw new Exception( "注释" );
} @Transactional (noRollbackFor=Exception. class ) //指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException( "注释" );
} |
Spring事务演示
创建UserDao接口,定义增加、修改方法:
1 2 3 public interface UserDao { 4 public void add(int age,int id); 5 public void update(int age,int id); 6 }
创建UserDaoImpl类实现接口方法:
1 2 3 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.jdbc.core.JdbcTemplate; 6 import org.springframework.stereotype.Component; 7 8 @Component 9 public class UserDaoImpl implements UserDao { 10 @Autowired 11 private JdbcTemplate jdbcTemplate; 12 public void add(int age,int id){ 13 String sql = "update user set age = age - ? where id = ?"; 14 jdbcTemplate.update(sql,age,id); 15 } 16 public void update(int age,int id){ 17 String sql = "update user set age = age + ? where id = ?"; 18 jdbcTemplate.update(sql,age,id); 19 } 20 }
创建配置类txConfig,开启事务,配置连接数据库信息
1 @Configuration 2 @ComponentScan(basePackages = "com.riven") 3 //开启事务 4 @EnableTransactionManagement 5 public class txConfig { 6 7 //创建数据库连接池 8 @Bean 9 public DruidDataSource getDruidDataSource() { 10 DruidDataSource dataSource = new DruidDataSource(); 11 dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); 12 dataSource.setUrl("jdbc:mysql:///test"); 13 dataSource.setUsername("root"); 14 dataSource.setPassword("root"); 15 return dataSource; 16 } 17 //创建JdbcTemplate 18 public JdbcTemplate getJdbcTemplate(DataSource dataSource) { 19 //自动到IoC容器中根据类型找到dataSource 20 JdbcTemplate jdbcTemplate = new JdbcTemplate(); 21 //注入DataSource 22 jdbcTemplate.setDataSource(dataSource); 23 return jdbcTemplate; 24 } 25 //创建事务管理器对象 26 @Bean 27 public DataSourceTransactionManager getDataSourceTx(DataSource dataSource){ 28 DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); 29 transactionManager.setDataSource(dataSource); 30 return transactionManager; 31 } 32 }
创建事务类UserService,定义事务
1 @Service 2 @Transactional 3 public class UserService { 4 @Autowired 5 private UserDaoImpl userDao; 6 public void accountMoney(){ 7 userDao.add(10,1); 8 //int i = 10/0; 9 userDao.update(10, 2); 10 } 11 }
测试类
1 public class Test { 2 public static void main(String[] args) { 3 ApplicationContext context = 4 new AnnotationConfigApplicationContext(txConfig.class); 5 UserService userService = context.getBean("userService",UserService.class); 6 userService.accountMoney(); 7 } 8 }