关于spring:spring注解驱动开发11-Spring声明式事务

2次阅读

共计 7009 个字符,预计需要花费 18 分钟才能阅读完成。

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());
    }
}

留神:

  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;

正文完
 0