Spring的事务控制

一、Spring的事务控制

  • 分层开发,事务处理位于业务层,Spring提供了分层设计业务层的事务处理解决方案。
  • Spring提供了一组事务控制的接口。这组接口是在spring-tx-4.2.4.RELEASE.jar中。
  • Spring的事务都是基于AOP的,既可以使用配置的方法实现,也可以使用注解的方法实现。

二、Spring事务控制的API介绍

  • PlatformTransactionManager
    这个接口是spring的事务管理器,它里面提供了常用的操作事务的方法。

    • 获取事务状态信息
      TransactionStatus getTransaction(TransactionDefinition definition)
    • 提交事务
      void commit(TransactionStatus status)
    • 回滚事务
      void rollback(TransactionStatus status)
    • 一般都会用它的实现类
      使用SpringJDBC或iBatis进行持久化数据时使用
      DataSourceTransactionManage
  • TransactionDefinition
    事务的定义信息对象,方法如下:

    • 获取事务对象名称
      Spring getName()
    • 获取事务隔离级
      int getIsolationLevel()
    • 获取事务传播行为
      int getPropagationBehavior()
    • 获取事务超时时间
      int getTimeout()
    • 获取事务是否只读
      boolean isReadOnly()
    • 事务的传播行为
      REQUIRED
      如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
      SUPPORTS
      支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
      MANDATORY
      使用当前的事务,如果当前没有事务,就抛出异常
      REQUERS_NEW
      新建事务,如果当前在事务中,把当前事务挂起。
      NOT_SUPPORTED
      以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
      NEVER
      以非事务方式运行,如果当前存在事务,抛出异常
      NESTED
      如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED
      类似的操作。
    • 超时时间
      默认值是-1,没有超时限制。如果有,以秒为单位进行设置
    • 是否是只读事务
      建议查询时设置为只读
  • TransactionStatus
    这个接口提供的是事务具体的运行状态

  • 刷新事务
    void flush()

  • 获取是否存在存储点
    boolean hasSavepoint()

  • 获取事务是否为新的事务
    boolean isNewTransaction()

  • 获取事务是否回滚
    boolean isRollbackOnly()

  • 设置事务回滚
    void setRollbackOnly()

三、XML的声明式事务控制配置方式

1.所需jar包

jar包

2.数据库

account数据库

并创建对应的实体类

3.编写业务层接口和实现类
IStuService.java

package com.edu.service;

/**
 * 业务层接口
 */
public interface IStuService {

    /**
     * 转账
     * @param sourceName
     * @param targetName
     * @param money
     */
    void transfer(String sourceName,String targetName,Float money);
}

StuServiceImpl.java

package com.edu.service.impl;

import com.edu.dao.IStuDao;
import com.edu.domain.Account;
import com.edu.service.IStuService;
/**
 * 业务层实现类
 */
public class StuServiceImpl implements IStuService {

    private IStuDao stuDao;

    public void setStuDao(IStuDao stuDao) {
        this.stuDao = stuDao;
    }

    @Override
    public void transfer(String sourceName, String targetName, Float money) {
        //1.根据名称查询账户信息
        Account account = stuDao.findAccountByName(sourceName);
        Account target = stuDao.findAccountByName(targetName);
        //2.转出账户减钱,转入账户加钱
        account.setMoney(account.getMoney()-money);
        target.setMoney(target.getMoney()+money);
        //3.更新账户信息
        stuDao.updateAccount(account);
        int i=1/0;//异常,检验事务的作用
        stuDao.updateAccount(target);
    }
}

4.编写dao接口和实现类

package com.edu.dao;

import com.edu.domain.Account;
/**
  * 持久层接口
  */
public interface IStuDao {
    /**
     * 根据名称查询账户信息
     * @param targetName
     * @return
     */
    Account findAccountByName(String targetName);

    /**
     * 更新账户信息
     * @param account
     */
    void updateAccount(Account account);
}
package com.edu.dao.Impl;

import com.edu.dao.IStuDao;
import com.edu.domain.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import java.util.List;
/**
  * 持久层实现类
  */
public class StuImpl extends JdbcDaoSupport implements IStuDao {
    

    @Override
    public Account findAccountByName(String targetName) {
        List accountList = getJdbcTemplate().query("select * from account where name = ?", new BeanPropertyRowMapper(Account.class), targetName);
        if (accountList.isEmpty()) {
            return null; //没有名称的账户
        }
        if (accountList.size() > 1) {
            //结果集不唯一,不要
            throw new RuntimeException("结果集不唯一,不要");
        }
        return accountList.get(0);
    }

    @Override
    public void updateAccount(Account account) {
        getJdbcTemplate().update("update account set name = ?,money = ? where cid = ?",account.getName(),account.getMoney(),account.getCid());
    }
}

5.配置配置文件
bean.xml






    




    




    
    
    
    





    
    




    
        
        
    




    
    
    
    



6.测试类

package com.edu.springTemplate;

import com.edu.service.IStuService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IStuService stuService = (IStuService) ac.getBean("stuService");
        /*Stu stu = stuService.findStuById(1);
        System.out.println(stu);*/
        stuService.transfer("aaa","bbb",100f);
    }
}

如果没有事务,若异常,账户信息无法回滚,也就是会造成一个账户的钱转了出去,但另一个账户却没有受到。但是有了事务,若有异常就会回滚,账户操作就会回到之前。

四、基于XML和注解组合使用的声明式事务配置

在上述案例基础上只需要修改

1.业务层实现类

package com.edu.service.impl;

import com.edu.dao.IStuDao;
import com.edu.domain.Account;
import com.edu.service.IStuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("stuService")
@Transactional
public class StuServiceImpl implements IStuService {

    @Autowired
    private IStuDao stuDao;

    @Override
    public void transfer(String sourceName, String targetName, Float money) {
        //1.根据名称查询账户信息
        Account account = stuDao.findAccountByName(sourceName);
        Account target = stuDao.findAccountByName(targetName);
        //2.转出账户减钱,转入账户加钱
        account.setMoney(account.getMoney()-money);
        target.setMoney(target.getMoney()+money);
        //3.更新账户信息
        stuDao.updateAccount(account);
        int i=1/0;
        stuDao.updateAccount(target);
    }
}

2.Dao层实现类

package com.edu.dao.Impl;

import com.edu.dao.IStuDao;
import com.edu.domain.Account;
import com.edu.domain.Stu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository("stuDao")
public class StuImpl implements IStuDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public Stu findStuById(Integer sid) {
        List list = jdbcTemplate.query("select * from stu where sid = ?", new BeanPropertyRowMapper(Stu.class), 1);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public Account findAccountByName(String targetName) {
        List accountList = jdbcTemplate.query("select * from account where name = ?", new BeanPropertyRowMapper(Account.class), targetName);
        if (accountList.isEmpty()) {
            return null; //没有名称的账户
        }
        if (accountList.size() > 1) {
            //结果集不唯一,不要
            throw new RuntimeException("结果集不唯一,不要");
        }
        return accountList.get(0);
    }

    @Override
    public void updateAccount(Account account) {
        jdbcTemplate.update("update account set name = ?,money = ? where cid = ?",account.getName(),account.getMoney(),account.getCid());
    }
}

3.配置配置类
bean.xml




    
    
    
    
        
    
    
    
        
        
        
        
    

    
    
    
        
        
    

    
    

    

测试类如上
效果也如上

五、基于纯注解的声明式事务配置

在基于XML和注解组合使用的声明式事务配置的基础上将xml文件种的配置转为注解

1.使用注解配置数据源

jdbcConfig.java

package com.edu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

/**
 * 使用注解
 *      配置JdbcTemplate
 *      配置数据源
 */
public class JdbcConfig {

    //配置JdbcTemplate
    @Bean(name = "jdbcTemplate")
    public JdbcTemplate createJdbcTemplate(DataSource dataSource){
        return new JdbcTemplate(dataSource);
    }

    //配置数据源
    @Bean(name = "dataSource")
    public DataSource createDataSource(){
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/goods");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

2.配置事务管理器
TransactionManager.java

package com.edu.config;

import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

/**
 * 事务控制配置类
 */
public class TransactionManager {

    @Bean(name = "transactionManager")
    public PlatformTransactionManager createTransactionManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
}

3.创建一个类用于加载spring的配置并指定要扫描的包
SpringConfig.java

package com.edu.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * Spring的配置类,作用就是当bean.xml用
 */
@Configuration
@ComponentScan("com.edu")
@Import({JdbcConfig.class,TransactionManager.class})
@EnableTransactionManagement
public class SpringConfig {

}

4.测试类

package com.edu.springTemplate;

import com.edu.config.SpringConfig;
import com.edu.service.IStuService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class Test {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        IStuService stuService = (IStuService) ac.getBean("stuService");
        stuService.transfer("aaa","bbb",100f);
    }
}

你可能感兴趣的:(Spring的事务控制)