Spring 事务解决方案

Spring 中的事务主要是利用 Aop 思想,简化事务的配置,可以通过 Java 配置也可以通过 XML 配置。

我们通过一个转账操作来看下 Spring 中的事务配置。

准备工作


创建数据库

CREATE DATABASE /*!32312 IF NOT EXISTS*/`test01` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `test01`;

/*Table structure for table `account` */

DROP TABLE IF EXISTS `account`;

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `money` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

/*Data for the table `account` */

insert  into `account`(`id`,`username`,`money`) values (1,'zhangsan',1000),(2,'lisi',1000);

配置 JdbcTemplate

提供一个配置类,在配置类中配置 JdbcTemplate

@Configuration
public class JdbcConfig {
    
    @Bean
    DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        dataSource.setUrl("jdbc:mysql:///test01");
        return dataSource;
    }
    
    @Bean
    JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(dataSource());
    }
}

数据持久层

@Repository
public class UserDao {
    
    @Autowired
    JdbcTemplate jdbcTemplate;

    public void addMoney(String username, Integer money) {
        jdbcTemplate.update("update account set money=money+? where username=?", money, username);
    }

    public void minMoney(String username, Integer money) {
        jdbcTemplate.update("update account set money=money-? where username=?", money, username);
    }
}

业务逻辑层

@Service
public class UserService {
    
    @Autowired
    UserDao userDao;
    
    public void updateMoney() {
        userDao.addMoney("zhangsan", 200);
        int i = 1 / 0;
        userDao.minMoney("lisi", 200);
    }
}

相关配置

最后,在 XML 文件中,开启自动化扫描:

<context:component-scan base-package="com.antoniopeng"/>

<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
    <property name="url" value="jdbc:mysql:///test01?serverTimezone=Asia/Shanghai"/>
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>

<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
</bean>

XML 配置


XML 中配置事务一共分为三个步骤:

1. 配置 TransactionManager

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

2. 配置事务要处理的方法

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="update*"/>
        <tx:method name="insert*"/>
        <tx:method name="add*"/>
        <tx:method name="delete*"/>
    </tx:attributes>
</tx:advice>

注意,一旦配置了方法名称规则之后,service 中的方法一定要按照这里的名称规则来,否则事务配置不会生效

3. 配置 AOP

<aop:config>
    <aop:pointcut id="pc1" expression="execution(* com.antoniopeng.hello.spring.service.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pc1"/>
</aop:config>

4. 测试

@Before
public void before() {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    jdbcTemplate = ctx.getBean(JdbcTemplate.class);
    userService = ctx.getBean(UserService.class);
}

@Test
public void test1() {
    userService.updateMoney();
}

Java 配置


如果要开启 Java 注解配置,在 XML 配置中添加如下配置:

<tx:annotation-driven transaction-manager="transactionManager" />

这行配置,可以代替下面两个配置:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="update*"/>
        <tx:method name="insert*"/>
        <tx:method name="add*"/>
        <tx:method name="delete*"/>
    </tx:attributes>
</tx:advice>
<aop:config>
    <aop:pointcut id="pc1" expression="execution(* org.javaboy.service.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pc1"/>
</aop:config>

然后,在需要添加事务的方法上,添加 @Transactional 注解,表示该方法开启事务,当然,这个注解也可以放在类上,表示这个类中的所有方法都开启事务。

@Service
public class UserService {
    
    @Autowired
    UserDao userDao;
    
    @Transactional
    public void updateMoney() {
        userDao.addMoney("zhangsan", 200);
        int i = 1 / 0;
        userDao.minMoney("lisi", 200);
    }
}

更多干货请移步:https://antoniopeng.com

posted @ 2021-02-04 08:46  彭楷淳  阅读(11)  评论(0编辑  收藏  举报