Spring 数据访问事务管理例子

以下内容均可参考官网

  • 点击查看官网

一、Spring声明式事务实现关键要点

1. 创建一个maven项目
2. 修改pom.xml

    4.0.0
    cn.lazyfennec
    SpringTransaction
    0.0.1-SNAPSHOT

    
        
            org.springframework
            spring-context
            5.3.18
        
        
            org.springframework
            spring-jdbc
            5.3.18
        
        
            org.springframework
            spring-aop
            5.3.18
        
        
            org.aspectj
            aspectjweaver
            1.9.9.1
            runtime
        
        
        
            mysql
            mysql-connector-java
            8.0.16
        
        
        
            org.apache.commons
            commons-dbcp2
            2.9.0
        
    

3. 新建db.properties,在resources目录下
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy?serverTimezone=GMT(数据库名称记得替换成你的)
jdbc.username=#### (替换成你的数据库账号)
jdbc.password=#### (替换成你的数据库密码)
4. 新建application-context.xml
  • 主要记得添加schema

xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"

http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"

  • 具体文件如下


    
    
    
    
    
        
        
        
        
    
    
    

5. 定义事务管理器
  • 在application-context.xml 中加入以下内容
    
    
        
    
6. 定义事务Advice
  • 在application-context.xml 中加入以下内容
    
    
        
            
            
            
            
        
    
7. 定义Pointcut
  • 在application-context.xml 中加入以下内容
    
    
        
        
    
8. 配置,参考 “6. 定义事务Advice
  • name:匹配的函数名称,支持*匹配
  • propagation:事务传播行为
  • isolation:事务隔离级别
  • timeout:超时
  • read-only:是否只读事务
  • rollback-for:触发回滚的异常,逗号分隔
  • no-rollback-for:不触发回滚的异常,逗号分隔
9. 开启注解方式@Transactional


  • value:
  • value:使用的TransactionManager
  • propagation:事务传播行为
  • isolation:事务隔离级别
  • timeout:超时
  • readOnly:是否只读事务
  • rollbackFor:触发回滚的异常类对象数组
  • rollbackForClassName:触发回滚的异常类名称数组
  • noRollbackFor:不触发回滚的异常类对象数组
  • noRollbackForClassName:不触发回滚的异常类名称数组
10. 创建Account,此时未添加事务
package cn.lazyfennec.entity;

/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/4/14 23:59
 */
public class Account {
    private int id;
    private String name;
    private Double money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

11. 创建AccoutDao
package cn.lazyfennec.dao;

import cn.lazyfennec.entity.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/4/14 23:54
 */
@Repository
public class AccountDao {

    private JdbcTemplate jdbcTemplate;

    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    /**
     * 重置所有账户余额为1000元
     */
    public void resetMoney() {
        jdbcTemplate.update("update account set money = 1000");
    }

    /**
     * 获取所有账户信息
     *
     * @return
     */
    public List listAccount() {
        return this.jdbcTemplate.query("select * from account", new RowMapper() {
            public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
                Account account = new Account();
                account.setId(rs.getInt("id"));
                account.setName(rs.getString("name"));
                account.setMoney(rs.getDouble("money"));
                return account;
            }
        });
    }

    /**
     * 转账
     *
     * @param source
     * @param target
     * @param money
     */
    public void transferMoney(String source, String target, double money) {
        this.jdbcTemplate.update("update account set money=money-? where name=?", money, source);
        throwException();
        this.jdbcTemplate.update("update account set money=money+? where name=?", money, target);
    }

      /**
     * 模拟抛出异常
     */
    private void throwException() {
        throw new RuntimeException("ERROR");
    }
}

12. 创建启动类
package cn.lazyfennec;

import cn.lazyfennec.dao.AccountDao;
import cn.lazyfennec.entity.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/4/15 0:01
 */
public class SpringTransaction {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        AccountDao dao = context.getBean("accountDao", AccountDao.class);
        dao.resetMoney();

        List accounts = dao.listAccount();
        for(Account account : accounts) {
            System.out.println(account);
        }
        try {
            dao.transferMoney("aaa", "bbb", 200);
        } catch (Exception e) {
            System.out.println(e.getMessage()); // 触发异常,自动回滚
        }
        System.out.println("========================================");
        accounts = dao.listAccount();
        for(Account account : accounts) {
            System.out.println(account);
        }
        ((ConfigurableApplicationContext) context).close();
    }

}

13.如果使用注解@Transactional
  • 首先application-context.xml中要加入以下内容
    
    
  • 此时,以下的内容可以删除

    
        
            
            
            
            
        
    

    
    
        
        
    
  • 修改AccountDao的transferMoney 如下所示:
    /**
     * 转账
     *
     * @param source
     * @param target
     * @param money
     */
    @Transactional(propagation = Propagation.REQUIRED) // 也可以使用默认
    public void transferMoney(String source, String target, double money) {
        this.jdbcTemplate.update("update account set money=money-? where name=?", money, source);
        throwException();
        this.jdbcTemplate.update("update account set money=money+? where name=?", money, target);
    }
14. 执行结果如下所示
Account{id=1, name='aaa', money=1000.0}
Account{id=2, name='bbb', money=1000.0}
Account{id=3, name='ccc', money=1000.0}
Account{id=6, name='fff', money=1000.0}
Account{id=8, name='eee', money=1000.0}
ERROR
========================================
Account{id=1, name='aaa', money=1000.0}
Account{id=2, name='bbb', money=1000.0}
Account{id=3, name='ccc', money=1000.0}
Account{id=6, name='fff', money=1000.0}
Account{id=8, name='eee', money=1000.0}

Process finished with exit code 0

二、编程式事务

  • TransactionTemplate
  • PlatformTransactionManager的实现
  • 定义TransactionTemplate
定义TransactionTemplate
  • 使用TransactionTemplate


    使用TransactionTemplate

    使用TransactionTemplate

    使用TransactionTemplate
  • PlatformTransactionManager的实现


    PlatformTransactionManager的实现

三、如何选择声明式事务和编程式事务

如何选择声明式事务和编程式事务

你可能感兴趣的:(Spring 数据访问事务管理例子)