spring注解驱动开发-(11)-Spring声明式事务

1.数据源pom依赖spring-jdbc:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>

mysql5.7的话, 注意依赖的版本:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

2.dao层:

2.1 数据库表结构:

CREATE TABLE `t_user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `age` int(3) DEFAULT NULL,
  `gender` varchar(20) DEFAULT NULL,
  `is_active` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

2.2 实体类 TUser.java

package com.niewj.bean;

import lombok.Data;

@Data
public class TUser {
    private int id;
    private String name;
    private int age;
    private String gender ;
}

2.3 数据访问DAO:

TUserDao.java

package com.niewj.dao;

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

import java.util.Random;
import java.util.UUID;

@Repository("userDao")
public class TUserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public int saveUser() {
        String name = UUID.randomUUID().toString().replaceAll("-","");
        int age = new Random().nextInt(35);
        String gender = "male";

        // 这里写了单引号会报错
        String insertSql = "insert into t_user(name, age, gender) values(?, ?, ?)";
        int updated = jdbcTemplate.update(insertSql, name, age, gender);

        // ---------
        doCalc();

        return updated;
    }

    // 做一些运算, 有可能异常, 如除法
    public void doCalc(){
        int value = 20/0;
    }
}

3.service层

TUserService.java

package com.niewj.service;

import com.niewj.dao.TUserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("userService")
public class TUserService {

    @Autowired
    private TUserDao userDao;

    @Transactional
    public void insertUser(){
        userDao.saveUser();
    }
}

4.配置类:

4.1 依赖properties

db.properties:

dev.mysql.url = jdbc:mysql://127.0.0.1/dev
dev.mysql.username = niewj
dev.mysql.password = 1234
dev.mysql.validationQuery = SELECT 1
dev.mysql.connectionProperties = useUnicode=true;characterEncoding=UTF8;rewriteBatchedStatements=true;socketTimeout=60000;autoReconnectForPools=true

4.2 注册spring的配置类:

TxConfig.java

package com.niewj.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
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.niewj.service", "com.niewj.dao"})
@Configuration
@EnableTransactionManagement
@PropertySource("classpath:/db.properties")
public class TxConfig {

    /**
     * dev 配置
     */
    @Value("${dev.mysql.url}")
    private String urlDev;
    @Value("${dev.mysql.username}")
    private String usernameDev;
    @Value("${dev.mysql.password}")
    private String passwordDev;
    @Value("${dev.mysql.connectionProperties}")
    private String connectionProperties;

    // 1. 注册 DataSource 数据源
    @Bean
    public DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setUrl(urlDev);
        ds.setUsername(usernameDev);
        ds.setPassword(passwordDev);
        ds.setValidationQuery("SELECT 1");
        ds.setConnectionProperties(connectionProperties);

        System.out.println("初始化-dev-DataSource");
        return ds;
    }

    /**
     * 2. 注册 JdbcTemplate 工具
     * @param dataSource 容器会自动从其内找到bean注入
     * @return
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
//        return new JdbcTemplate(dataSource()); // 调用也可以, 不会重复创建
        return new JdbcTemplate(dataSource);
    }

    /**
     * 3. 注册 事务管理器 PlatformTransactionManager(DataSourceTransactionManager)
     *  这里使用调用 dataSource()方法, 也可以写入参传入
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager(){
        return new DataSourceTransactionManager(dataSource());
    }
}

4.2.1 注意:

  1. 事务功能需要事务管理器TransactionManager, 事务管理器依赖数据源DataSource;

  2. Dao操作依赖JdbcTemplate, JdbcTemplate也依赖数据源DataSource;

  3. 注入@Bean依赖,可以通过参数, 也可以通过调用方法:

    3.1: JdbcTemplate是通过方法入参指定依赖的数据源对象;

    3.2: PlatformTransactionManager是通过方法调用指定数据源对象;

    这两种方式都可以实现IOC容器从容器中自动检索注入依赖对象的功能;

  4. 注意这里的几个要点

    @ComponentScan({“com.niewj.service”, “com.niewj.dao”})

    扫描需要注册到容器中的bean的位置;

@Configuration

声明当前类为配置类, 需要注册到spring上下文然后重新refresh加载上下文;

@EnableTransactionManagement

开启事务管理支持, 相当于xml的:

<tx:annotation-driven />

@PropertySource(“classpath:/db.properties”)

类中使用到的@Value属性定位的目标配置文件;

5. 测试用例入口:

package com.niewj;

import com.niewj.config.TxConfig;
import com.niewj.service.TUserService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.stream.Stream;

/**
 * spring 声明式事务-测试
 */
public class TxTest {

    @Test
    public void testTx() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TxConfig.class);

        // 打印spring容器中的 BeanDefinition
        Stream.of(ctx.getBeanDefinitionNames()).forEach(e -> System.out.println(e));
        System.out.println("=============================");

        TUserService userService = ctx.getBean(TUserService.class);
        userService.insertUser();

        ctx.close();
    }

}

output: 控制台输出:

注意需要的bean都被初始化了:

txConfig

userService

userDao

dataSource

jdbcTemplate

transactionManager

初始化-dev-DataSource
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
txConfig
bookService
productService
userService
bookDao
userDao
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
org.springframework.transaction.config.internalTransactionAdvisor
transactionAttributeSource
transactionInterceptor
org.springframework.transaction.config.internalTransactionalEventListenerFactory
dataSource
jdbcTemplate
transactionManager
org.springframework.aop.config.internalAutoProxyCreator
=============================
七月 20, 2020 5:19:29 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-1} inited
Mon Jul 20 17:19:29 CST 2020 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.

java.lang.ArithmeticException: / by zero

    at com.niewj.dao.TUserDao.doCalc(TUserDao.java:33)
    at com.niewj.dao.TUserDao.saveUser(TUserDao.java:26)
    at com.niewj.service.TUserService.insertUser(TUserService.java:16)
    at com.niewj.service.TUserService$$FastClassBySpringCGLIB$$5996298d.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
.............

在操作遇到 除零异常时, 会发现mysql事务会回滚! over~

6.要点小结

6.1 业务层@Transactional注解事务方法;

6.2 配置类要注册TransactionManager及依赖DataSource;

6.3 配置类要开启事务@EnableTransactionManagement;


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 hi@niewj.com

×

喜欢就点赞,疼爱就打赏