使用Spring管理事务

事务的作用

事务是为了保证数据的安全性,完整性,一致性等问题。

事务是具有边界的,事务有开始,提交和回归等边界。

事务的性质有原子性,一致性,隔离性,持久性。

使用JDBC API定义事务边界

新建maven项目,添加依赖

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.3.176</version>
</dependency>

该依赖用来使用轻量级的数据库h2

打开h2数据库,新建表和添加记录

H2数据库的打开方式是在添加的jar包中找到org.h2.tools.Console类,运行它。

Create table account(

Id bigint identity primary key,

Owner_name varchar(255),

Balance double,

Access_time timestamp,

Locked Boolean

);

Insert into account values(100,’owner-1’,10,’2020-02-14’,false);

Insert into account values(101,’owner-2’,0,’2020-02-14’,false);

新建Accountserviece接口并实现,完成转账功能

public class AccountSerivceImpl implements AccountService {

    public void transferMoney(long sourceAccountId,long targetAccountId,double amount){

        Connection connection = null;

        try{

            DriverManager.registerDriver(new Driver());

            connection = DriverManager.getConnection("jdbc:h2:tcp://localhost/~/test","sa","");

            connection.setAutoCommit(false);

            Statement statement = connection.createStatement();

            String sql1 = "update account set balance = balance - " + amount + " where id = " + sourceAccountId;

            String sql2 = "update account set balance = balance + " + amount + " where id = " + targetAccountId;

            statement.executeUpdate(sql1);

            statement.executeUpdate(sql2);

            connection.commit();

        }catch (SQLException e){

            try{

                connection.rollback();

            }catch (SQLException s){



            }

            throw new RuntimeException(e);

        }finally {

            try{

                connection.commit();

            }catch (SQLException s){



            }

        }

    }

}

在main方法中转账,并观察数据库·1

public static void main(String[] args) {

    AccountService service = new AccountSerivceImpl();

    service.transferMoney(100L,101L,5.0d);

}

实例说明

使用DriverManager.registerDriver方法来注册h2数据的驱动。也可用Class.forName()的方法来注册驱动。

JDBCAPI中用connection.setAutoCommit(false)来激活事务,否则sql语句被单句执行。

用connection.commit()来提交事务。

用connection.rollback()来回滚。

最后关闭connection资源。

在Spring容器中配置PlatformTransactionManagerBean

添加Maven依赖

<dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-context</artifactId>

    <version>4.0.5.RELEASE</version>

</dependency>

<dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-tx</artifactId>

    <version>4.0.5.RELEASE</version>

</dependency>

<dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-jdbc</artifactId>

    <version>4.0.5.RELEASE</version>

</dependency>

创建bean配置类

@org.springframework.context.annotation.Configuration

public class Configuration {

    @Bean

    public DataSource dataSource(){

        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName("org.h2.Driver");

        dataSource.setUrl("jdbc:h2:tcp://localhost/~/test");

        dataSource.setUsername("sa");

        dataSource.setPassword("");

        return dataSource;

    }

    @Bean

    public PlatformTransactionManager transactionManager(){

        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();

        transactionManager.setDataSource(dataSource());

        return transactionManager;

    }

}

在main方法检测PlatformTransactionManager是否获取

public class Main {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Configuration.class);

        PlatformTransactionManager transactionManager = applicationContext.getBean(PlatformTransactionManager.class);

        System.out.println(transactionManager != null);

    }

}

示例说明

Spring的事务抽象模型基于PlatformTransactionManager接口。作为开发人员,需要根据不同的数据库技术选用不用的实现。

全局事务和本地事务

本地事务就是只在单一数据库上进行的事务。

而全局事务的操作设计多个数据库,意味着分布式事务管理。

JEE提供了JTA来进行全局事务的管理。但是使用JTA的成本较高,且大多数应用并没有使用全局事务。所以在TransactionManager接口有多种实现,分别针对全局事务和本地事务。

在进行全局事务和本地事务进行切换时,只需要改变相应的Bean,而不用改变对应的业务逻辑。

在Spring中启用声明式事务管理

修改AccountServiceImpl类

public class AccountSerivceImpl implements AccountService {
    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    @Transactional
    public void transferMoney(long sourceAccountId, long targetAccountId, double amount){
        Connection connection = DataSourceUtils.getConnection(dataSource);
        try{
            Statement statement = connection.createStatement();
            String sql1 = "update account set balance = balance - " + amount + " where id = " + sourceAccountId;
            String sql2 = "update account set balance = balance + " + amount + " where id = " + targetAccountId;
            statement.executeUpdate(sql1);
            statement.executeUpdate(sql2);
        }catch (SQLException e){
            throw new RuntimeException(e);
        }finally {
            DataSourceUtils.releaseConnection(connection,dataSource);
        }
    }
}

在bena配置类中添加AccountServiceImpl类

@Bean
public AccountService accountService(){
    AccountSerivceImpl accountSerivce = new AccountSerivceImpl();
    accountSerivce.setDataSource(dataSource());
    return accountSerivce;
}

在配置类上加@EnableTransactionManagement注解

在main方法中执行transfer方法

public static void main(String[] args) {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Configuration.class);
    AccountService accountService = applicationContext.getBean(AccountService.class);
    accountService.transferMoney(100l,101l,5.0d);
}

示例说明

在配置类上添加@EnableTransactionManagement注解是为了在bean中检测有@transactonal的方法。

事务是具有边界的,必须定义事务开始,提交,回滚的地方。

而使用了@Transactional的方法自动定义事务边界,在操作没V 有异常发生时自动提交,有RuntimeException及其子类异常会自动回滚。

使用TransactionTemplate进行编程式事务管理

修改AccountServiceImpl中的transferMoney方法添加TransacTemplate属性。

private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {

    this.transactionTemplate = transactionTemplate;

}
public void transferMoney(final long sourceAccountId, final long targetAccountId, final double amount) {

    transactionTemplate.execute(new TransactionCallbackWithoutResult() {

        @Override

        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {

            Account sourceAccount = accountDao.find(sourceAccountId);

            Account targetAccount = accountDao.find(targetAccountId);



            sourceAccount.setBalance(sourceAccount.getBalance() - amount);

            targetAccount.setBalance(targetAccount.getBalance() + amount);



            accountDao.update(sourceAccount);

            accountDao.update(targetAccount);

        }

    });

}

在Configuration类中添加Bean

@Bean

public TransactionTemplate transactionTemplate(){

    TransactionTemplate transactionTemplate = new TransactionTemplate();

    transactionTemplate.setTransactionManager(transactionManager());

    return transactionTemplate;

}
@Bean

public AccountService accountService(){

    AccountServiceImpl accountSerivce = new AccountServiceImpl();

    accountSerivce.setAccountDao(accountDao());

    accountSerivce.setTransactionTemplate(transactionTemplate());

    return accountSerivce;

}

在main方法检测用例

示例说明

使用TransactionTemplate是Spring提供的编程式事务方法。

该类用了模板方法,把需要执行的算法步骤作为回调方法在匿名类中实现。

即用transaction.execute().新建TransactionCallBackWithoutResult匿名类。实现doInTransactionCallBackWithoutResult方法。

使用PlatformTransactionManager API进行编程式事务管理

修改AccountServiceImpl类

private PlatformTransactionManager transactionManager;
public void setTransactionManager(PlatformTransactionManager transactionManager) {

    this.transactionManager = transactionManager;

}
public void transferMoney(final long sourceAccountId, final long targetAccountId, final double amount) {

    TransactionDefinition definition = new DefaultTransactionDefinition();

    TransactionStatus status = transactionManager.getTransaction(definition);

    try{

        Account sourceAccount = accountDao.find(sourceAccountId);

        Account targetAccount = accountDao.find(targetAccountId);

        sourceAccount.setBalance(sourceAccount.getBalance() - amount);

        targetAccount.setBalance(targetAccount.getBalance() + amount);

        accountDao.update(sourceAccount);

        accountDao.update(targetAccount);

        transactionManager.commit(status);

    }catch (Exception e){

        transactionManager.rollback(status);

        throw new RuntimeException(e);

    }

}

修改bean配置类

@Bean

public AccountService accountService(){

    AccountServiceImpl accountSerivce = new AccountServiceImpl();

    accountSerivce.setAccountDao(accountDao());

    accountSerivce.setTransactionManager(transactionManager());

    return accountSerivce;

}

示例说明

TransactionDefinition是编程式事务的配置。

使用transaction.getTransaction(definition)表示着事务的开始。

在try代码块中进行业务逻辑后,用transaction.commit(status)提交事务。

在catch代码块中执行回滚。

Spring推荐使用transactionTemplate而不是Transactionmanager进行编程式事务。

编程式事务与声明式事务区别在于是否需要定义事务边界。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值