Springboot中的数据库事务

对于一些业务网站而言 , 产 品库存的扣减、 交易记录以及账户都必须是要么 同时成功, 要么 同时失败 ,这便是一种事务机制,而在一些特殊的场景下 ,如一个批处理 ,它将处理多个交易 ,但是在一些交易中发生了异常 , 这个时候则不能将所有的交易都回滚。如果所有的交易都回渎,那么那些本能够正常处理的业务也无端地被回滚。 通过 Spring 的数据库事务传播行为,可以很方便地处理这样的场景 。

首先配置数据库信息

spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver=com.mysql.jdbc.Driver
spring.datasource.tomcat.max-idle=10
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.max-wait=10000
spring.datasource.tomcat.initial-size=5

一、JDBC数据库事务

@Service
public class JdbcServiceImpl implements JdbcService{

	@Autowired
	private DataSource dataSource=null;

	@Override
	public int insertUser(String name,String note){
        Connection conn=null;
        int result=0;
        try{
            //获取连接
            conn=dataSource.getConnection();
            //开启事务
            conn.setAutoCommit(false);
            //设置隔离级别
            conn.setTransactionIsolation(TransactionIsolationLevel.RRAD_COMMITED.getLevel());
            //执行SQL
            PreparedStatement ps=conn.prepareStatement("insert into t_user(user_name,note)values(?,?)");
            ps.setString(1,userName);
            ps,setString(2,note);
            result=ps.executeUpdate();
            //提交事务
            conn.commit();
        }catch(Exception e){
            //回滚事务
            if(conn !=null){
                try{
                    conn.rollback();
                }catch(SqlException e1)
                    e1.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally{
            try{
                if(conn !=null && !conn.isClosed()){
                    conn.close()
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
        return result;
	}
}

 

使用JDBC需要使用大量的try...catch...finally...语句,和关于连接的获取关闭,事务的提交和回滚。使用Hibernate、myBatis可以减少try...catch...finally的使用,但是依旧不能减少开闭数据库连接和事务控制的代码。而AOP可以解决这样的问题。

二、Spring 声明式事务的使用

Spring AOP 会把我们的代码织入到约定的流程中,同样,同样执行的SQL的代码也可以织入的哦Spring 约定的数据库事务的流程中。首先要掌握这个约定

1.Spring 声明式数据库事务约定

对于事务需要通过标注告诉Spring在什么地方启用数据库事务功能,对于声明式数据库,是使用@Transactional进行标注的。

@Transactional 这个注解可以标注类和方法上,当它标注在类上时,代表这个类所有公共(public)非静态的方法东将启用事务功能。在@Transactonal 中还可以进行事务的隔离级别和传播行为,异常类型的配置。这些配置,是在Sprng IoC容器在加载时就会将这些配置信息解析出来,然后帮这些喜喜存储到事务定义器(TransactonDefinition接口实现的类)里,并且记录了那些类或者方法需要启动事务的功能,采取什么策略去执行事务。在这个过程中我们所需要做的就是给需要事务的类和方法标注@Transactional并配置属性

spring的事务处理机制

 

 

Spring 通过对注解@Transactional 属性配置去设置数据库事务 , 跟着 Spring 就会
开始调用开发者编写 的业务代码 。 执行开发者 的业务代码,可能发生异常,也可能不发生异常 。 在Spring 数据库事务 的流程 中,它会根据是否发生异常采取不同的策略 如果都没有发生异常, Spring 数据库拦截器就会帮助我们提交事务 , 这点也并不需要我们干预 。如果发生异常,就要判断一次事务定义器内的配置,如果事务定义器己经约定了该类型的异常不回段事务就提交事务 , 如果没有任何配置或者不是配置不回滚事务的异常,则会回滚事务,并且将异常抛出 , 这步也是由事务拦截器完成的。论发生异常与否, Spring 都会释放事务资源,这样就可以保证数据库连接池正常可用了,这
也是由 Spring 事务拦截器完成的内容 。

public class UserServiceImpl implements UserService{
    
    @Autowired
    private UserDao userDao=null;
    
    @Override
    @Transactional
    public int insertUser(User user){
        return userDao.insertUser(user);
    }
}

 

2.@Transactional配置项

spring中关于数据库属性是由@Transactional 来配置的,源码如下所示

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetenttionPolicy.RUNTIME)
@InHerited
@Documented
public @interface Transactional{
    //通过bean name指定事务管理器
    @ALiasFor("transactionManager")
    String value() default"";
    
    //同value属性
    @ALiasFor(value)
    String transactionManager() default"";
    
    //指定传播行为
    Propagation propagation() default Propagetion.REQUIRED;
    
    //指定隔离级别
    Isolation isolation() default IsoLation.DEFAULT
    
    //指定超时时间(单位为秒)
    int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
        
    //时候只读事务
    boolean readOnly() default false;
    
    //方法发生指定异常时回滚,默认是所有的异常都回滚
    Class<? extends Throwable>[] rollbackFor() default();
    
    //方法发生指定异常名称时回滚,默认是所有异常都回滚
    String[] rollbackForClassName() default();
    
    //方法发生指定异常时不回滚,默认是所有的 异常都回滚
    Class<? extends Throwable>[] noRollBackFor() default();
    
    //方法在发生指定异常名称时不回滚,默认所有异常都回滚
    String noRollbackForClassName() default();
}
  • value和transactionManager属性是配置一个Spring的事务管理器
  • timeout是事务允许存在的时间戳
  • read Only 属性 定义的是事务是否是只读事务;
  • rollbackFor 、 rollbackForClassName 、 noRollbackFor 和 noRollbackForClassName 都是指定异常 ,我们从流程中可以看到在带有事务的方法时,可能发生异常,通过这些属性的设置可以指定在什么异常的情况下依旧提交事务,在什么异常的情况下回滚事务 , 这些可以根据自己的需要进行指定
  • propagation 传播行为(重点)
  • isolation隔离级别(重点)

@Transactional可以放在接口上也可以放在实现类上,spring推荐放在实现类上。

3.Spring 事务管理器

在spring的事务流程中事务的打开回滚和提交是由事务管理器来完成的。事务管理器的顶层接口是PlatformTransactionManager.

 

当我们使用myBatis框架时最常用的的是DataSourceTransactionManager它实现了PlatformTransactionManager接口,关于PlatformTransactionManager的源码如下


public interface PlatformTransactionManager{
    //获取事务,它还会设置数据属性
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    
    //提交事务
    void commit(TransactionStatus status) throws TransactionException;          
    
    //回滚事务
    void rollback(TransactionStatus status) throws TransactionException;
}

Spring在事务管理时,就是将这些方法按照约定织入对应的流程,其中getTransaction方法的参数是一个事务定义器,它依赖于我们配置的@Transactional的配置项生成的。于是通过它就能够设置事务的属性了

在 Spring Boot 中,当你依赖于 mybatis-spring-boot-starter 之后 , 它会自动创建一个 DataSourceTransactionManager 对象 ,作为事务管理器 ,如果依赖于 spring-boot-starter-data-j pa ,则它会自动创建JpaTransactionManager 对象作为事务管理器 ,所以我们一般不需要自己创建事务管理器而直接使用它们即可。

4.事务的使用

创建一张表

create table t_user(
	id int(12) auto_increment,
	user_name varchar(60) not null,
	note varchar(512),
	primary key(id)
);

创建POJO

package com.demo.dao

@Repository
public interface UserDao{
    User getUser(Long id);
    int intsertUser(User user);
}

服务接口实现类

package com.demo.service.demo

@Service
public class UserServiceImpl implements UserService{	
    @Autowired
    private UserDao userDao=null;
    
    @Override
    @Transactional(isolation=Isolation.READ_COMMITTED,timeout=1)
    public int insertUser(User user){
    	return userDao.insertUser(user);
    }
    
    @Override
    @Transactional(isolation=Isolation.READ_COMMITTED,timeout=1)
    public User insertUser(id){
        return userDao.getUser(id);
    }
}

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值