Spring之路(40)–使用@Transactional进行声明式事务管理如此简单

1. 足够简单

说实话要实现事务管理,给一个方法添加一个注解,则该方法自动实现事务,足够简单了,我也没法想还有更简单的么。


这个注解就是@Transactional,就是这么优秀。所谓的声明式事务管理,就是通过在方法(或类)上添加注解声明来启用事务的方式。


2. 声明式事务实例

第一,正常的编写数据对象Do与数据库表blog对应:

package org.maoge.transactionaldemo;
/**
 * @theme 数据对象--博客
 * @author maoge
 * @date 2020-01-27
 */
public class BlogDo {
    private Long id;
    private String title;
    private String author;
    private String content;
    // 省略get get
}

第二,编写数据库操作类,通过NamedParameterJdbcTemplate 操作数据库。

package org.maoge.transactionaldemo;
import java.util.HashMap;
import java.util.Map;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
/**
 * @theme DAO--博客
 * @author maoge
 * @date 2020-01-29
 */
public class BlogDao {
    public NamedParameterJdbcTemplate getNamedTemplate() {
        return namedTemplate;
    }
    public void setNamedTemplate(NamedParameterJdbcTemplate namedTemplate) {
        this.namedTemplate = namedTemplate;
    }
    private NamedParameterJdbcTemplate namedTemplate;
    /**
     * 新增
     */
    public void insert(BlogDo blog) {
        Map<String, Object> map = new HashMap<>();
        map.put("author", blog.getAuthor());
        map.put("content", blog.getContent());
        map.put("title", blog.getTitle());
        // 注意使用:xxx占位
        namedTemplate.update("insert into blog(author,content,title)values(:author,:content,:title)", map);
    }
}

第三,编写BlogService,调用BlogDao类型对象操作数据库。此处注意我们在方法addTwoBlog上添加了注解@Transactional,这样就开启了事务。

package org.maoge.transactionaldemo;
import org.springframework.transaction.annotation.Transactional;
public class BlogService {
    public BlogDao getBlogDao() {
        return blogDao;
    }
    public void setBlogDao(BlogDao blogDao) {
        this.blogDao = blogDao;
    }
    private BlogDao blogDao;
    @Transactional
    public void addTwoBlog() {
        BlogDo blog = new BlogDo();
        blog.setContent("测试");
        blogDao.insert(blog);
        int a = 1 / 0;// 发生异常,导致事务回滚,所以并不会插入任何一行数据
        blogDao.insert(blog);
    }
}

第四,通过配置类激活声明式事务,并且将个类注册为组件,这里跟之前的区别就是添加了@EnableTransactionManagement // 激活基于注解的声明式事务

package org.maoge.transactionaldemo;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.support.TransactionTemplate;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration // 表明该类是Spring配置类,需要扫描该类的配置信息
@EnableTransactionManagement // 激活基于注解的声明式事务
public class SpringConfig {
    /**
     * 定义数据源bean
     */
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8");
        dataSource.setUsername("root");
        dataSource.setPassword("Easy@0122");
        return dataSource;
    }

    /**
     * 定义事务管理bean
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());// 注入dataSource
        return transactionManager;
    }

    /**
     * 定义TransactionTemplate类型的bean
     */
    @Bean
    public TransactionTemplate transactionTemplate() {
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(transactionManager());// 注入事务管理器
        return transactionTemplate;
    }

    /**
     * 配置namedParameterJdbcTemplate组件
     */
    @Bean
    public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {
        NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(dataSource());// 注入dataSource
        return template;
    }

    /**
     * 为BlogDao注册bean
     */
    @Bean
    public BlogDao blogDao() {
        BlogDao blogDao = new BlogDao();
        blogDao.setNamedTemplate(namedParameterJdbcTemplate());// 注入namedParameterJdbcTemplate
        return blogDao;
    }

    /**
     * 为BlogService注册bean
     */
    @Bean
    public BlogService blogService() {
        BlogService blogService = new BlogService();
        blogService.setBlogDao(blogDao());// 注入blogDao
        return blogService;
    }
}

第五,测试

package org.maoge.transactionaldemo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
    public static void main(String[] args) {
        // 获取容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 容器中获取数据库操作组件
        BlogService blogService = (BlogService) context.getBean("blogService");
        blogService.addTwoBlog();
    }
}

当执行addTwoBlog中的int a = 1 / 0;时,发生异常,导致事务回滚,所以并不会插入任何一行数据。


3. 总结

声明式注解太简单了,首先通过@EnableTransactionManagement激活注解,然后需要开启事务的方法上添加@Transactional即可。


本篇组件采用了JavaConfig的配置方式,实际上对于BlogDao、BlogService可以通过在类上添加注解@Repository、@Service或@Component的方式将其注册为bean,效果是一样的。

上一篇:设计模式之6个创建模式


下一篇:阿里安全潘多拉实验室的研究人员揭秘如何完美越狱苹果iOS11.2.1