注解版的声明式事务

搭建声明式事务的环境

是个人都知道,在对数据库进行增删改操作时,必然是要使用到事务的。因此,接下来,我们就来搭建好声明式事务的基本环境。

导入相关依赖

首先,在项目的pom.xml文件中添加c3p0数据源的依赖,如下所示。

   <!--数据源-->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.44</version>
        </dependency>

        <!--添加spring-jdbc模块的依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>

Spring简化了对数据库的操作,只要我们在项目中导入了以上spring-jdbc模块的依赖,那么它就可以简化对数据库的操作以及事务控制。我们在后面就可以用Spring提供的JDBC模板(即JdbcTemplate)来操作数据库。

配置数据源以及JdbcTemplate

1、首先,我们得向IOC容器中注册一个c3p0数据源,那么如何做到这一点呢?很简单,先新建一个配置类,例如TxConfig,再使用@Bean注解向IOC容器中注册一个c3p0数据源

2、向IOC容器中注册一个JdbcTemplate组件,它是Spring提供的一个简化数据库操作的工具,它能简化对数据库的增删改查操作

package com.baidu.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration
public class TxConfig {

    // 注册c3p0数据源
    @Bean
    public DataSource dataSource() throws Exception {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/profile");
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }
}

数据库

创建一个数据库,新家一个表(tbl_user)

CREATE TABLE `tbl_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `age` int(2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

表建好之后,我们就来说说开发需求,其实很简单,就是向tbl_user表中插入一条记录。接下来,我们就来编码实现这个需求。

开发dao层

新建一个UserDao类,代码如下所示:

package com.baidu.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void insert() {
        String sql = "insert into `tbl_user`(username, age) values(?, ?)";

        String username = UUID.randomUUID().toString().substring(0, 5);
        jdbcTemplate.update(sql, username, 19); // 增删改都来调用这个方法
    }

}

注意,该类上标注了一个@Repository注解,因为待会我们要用到@ComponentScan注解来配置包扫描。

开发UserService层

新建一个UserService类,代码如下所示:

package com.baidu.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    @Transactional
    public void insertUser(){
        userDao.insert();
        System.out.println("插入成功.....");

        int i = 10/0;
    }
}

可以看到,现在默认insertUser()方法是没有任何事务特性的。如果这个方法上有事务,那么只要这个方法里面有任何一句代码出现了问题,该行代码之前执行的所有操作就都应该回滚。

此外,还应注意到,该类上标注了一个@Service注解。

接下来,我们就要在TxConfig配置类上添加@ComponentScan注解来配置包扫描了,如下所示。

package com.baidu.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@ComponentScan("com.baidu.tx")
@Configuration
public class TxConfig {

    // 注册c3p0数据源
    @Bean
    public DataSource dataSource() throws Exception {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/profile");
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }
}

至此,声明式事务的基本环境,我们就搭建好了,接下来就是来进行测试了。

测试

新建一个单元测试类,例如IOCTest_tx,代码如下所示:

import com.baidu.tx.TxConfig;
import com.baidu.tx.UserService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_tx {

    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);

        UserService userService = context.getBean(UserService.class);
        userService.insertUser();

        context.close();
    }

}

测试:插入成功!!

接下来,我们就为UserService类中的insertUser()方法添加上事务,添加上事务以后,只要这个方法里面有任何一句代码出现了问题,那么该行代码之前执行的所有操作就都应该回滚。

如果要想为该方法添加上事务,那么就得使用@Transactional注解了。我们在该方法上标注这么一个注解,就是为了告诉Spring这个方法它是一个事务方法,这样,Spring在执行这个方法的时候,就会自动地进行事务控制。如果该方法正常执行,没出现任何问题,那么该方法中的所有操作都会生效,最终就会提交;如果该方法运行期间出现异常,那么该方法中的所有操作都会回滚。

@Transactional
public void insertUser() {
	userDao.insert();
	// otherDao.other(); // 该方法中的业务逻辑势必不会像现在这么简单,肯定还会调用其他dao的方法
	System.out.println("插入完成...");
	
	int i = 10 / 0;
}

为insertUser()方法标注了@Transactional注解之后,那么它是不是就真的变成了一个事务方法呢?为了验证这一点,我们特地在该方法中故意抛出了一个算术异常。

目前tbl_user表中是只有一条记录的,如果insertUser()方法真的变成了一个事务方法,那么执行该方法再向tbl_user表中插入一条记录时,肯定是会出现问题的,既然出现了问题,插入操作势必就会回滚,最终tbl_user表中是不会再插入一条新记录的。

那么到底是不是这样的呢?我们拭目以待,运行完IOCTest_tx类中的test01()方法之后,虽说Eclipse控制台是打印出了插入完成…这样的消息,而且也给我们看到了除零的算术异常,但是刷新tbl_user表之后,你会发现仍然会向tbl_user表中插入一条新的记录,如下图所示。
在这里插入图片描述
这说明,虽然insertUser()方法是标注了@Transactional注解,但是它并不是一个真正的事务方法。

也就是说,光为insertUser()方法加一个@Transactional注解是不行的,那我们还得做什么呢?还得在TxConfig配置类上标注一个@EnableTransactionManagement注解,来开启基于注解的事务管理功能。

注意:像Spring的spring-jdbc模块,以及MyBatis框架等等这些想要进行事务控制,都需要用到这个DataSourceTransactionManager实现类。

接下来,我们就向IOC容器中注册事务管理器,即需要向TxConfig配置类中添加一个如下方法。

package com.baidu.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@EnableTransactionManagement //开启注解的事务管理功能;
@ComponentScan("com.baidu.tx")
@Configuration
public class TxConfig {

    // 注册c3p0数据源
    @Bean
    public DataSource dataSource() throws Exception {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/profile");
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }

    // 注册事务管理器在容器中
    @Bean
    public PlatformTransactionManager platformTransactionManager() throws Exception {
        return new DataSourceTransactionManager(dataSource());
    }




}

如果是像以前一样基于配置文件来开发,那么就得在配置文件中添加如下这样一行配置,来开启基于注解的事务管理功能。

<tx:annotation-driven/>

好,现在我们再来运行一下IOCTest_tx类中的test01()方法,至此材质一个真正的事务操作,业务逻辑代码出现报错,回滚!整个业务不会发生数据库的改变!

https://liayun.blog.csdn.net/article/details/111705550

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值