文档章节

spring-102-spring全注解快速实现事务

haoran_10
 haoran_10
发布于 2016/07/15 16:44
字数 1022
阅读 16
收藏 0

之前使用jdbc操作数据库,并使用事务的时候是这样操作:

    Connection connection = null;
        try {
            //connection = getConnection(....);//1.封装获取connection
            connection.setAutoCommit(false);   //2.设置为手动提交事务

            String execSql = "select 0";
            PreparedStatement ps =        connection.prepareStatement(execSql);//3.获取PreparedStatement
            ps.executeUpdate();//4.执行语句
            
            connection.commit(); //5.如果所有sql语句成功,则提交事务
            
            ps.close();//6.关闭
            connection.close();
        } catch (Exception e) {
            connection.rollback();//7.有错误回滚
            
            connection.close();
        }

呃,代码太臃肿了。不过幸亏有了spring,开发效率提升不知道多少倍。

OK,直接引入spring

本文是基于全注解,没有一丝xml代码配置。

1.数据库配置

所有的数据库操作,首先要有一个数据库,这里使用内存数据库h2

如下,代码清单1:

package wang.conge.springdemo.transaction.config;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;

@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource dataSource() {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        EmbeddedDatabase h2db = builder
            .setType(EmbeddedDatabaseType.H2) //H2
            .addScript("db/sql/create-db.sql")
            .addScript("db/sql/insert-data.sql")
            .build();
        
        return h2db;
    }
}

上述创建数据库的过程中,执行了两个SQL初始文件,非常简单,一个创建表,一个插入一些简单数据。

如下,代码清单2,3:

CREATE TABLE users (
  id     INTEGER PRIMARY KEY,
  name   VARCHAR(30),
  email  VARCHAR(50)
);

INSERT INTO users VALUES (1, 'kaka', 'kaka@qq.com');
INSERT INTO users VALUES (2, 'alex', 'alex@163.com');
INSERT INTO users VALUES (3, 'lucy', 'lucy@gmail.com');

2.开启spring事务

如下,代码清单4:

package wang.conge.springdemo.transaction.config;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
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;

@Configuration
@EnableTransactionManagement
public class DBCommonConfig {
    
    @Bean
    public PlatformTransactionManager transactionManager(DataSource datasource){
        return new DataSourceTransactionManager(datasource);
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource datasource){
        return new JdbcTemplate(datasource);
    }
    
}
  • 代码使用EnableTransactionManagement注解,开启spring事务
  • 使用DataSourceTransactionManager去管理事务,基于数据库连接池
  • 使用JdbcTemplate 简单封装去操作数据库

3.业务代码

模拟一个插入表数据,查询表,即使用JdbcTemplate非常简单。

如下,代码清单5:

package wang.conge.springdemo.transaction.service;

import java.util.List;
import java.util.Map;

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

@Transactional
@Service
public class UserDao {
    @Autowired JdbcTemplate jdbcTemplate;
    
    private final String insert_sql = "INSERT INTO users(id,name,email) VALUES (?, ?,?)";
    
    private final String query_sql = "select id,name,email from users";
    
    public void testInsert(int id,String name,String email){
        jdbcTemplate.update("update users set name = ? where id = ?","kakanew",1);//这句一定正常执行
        
        System.out.println("执行正常SQL后结果:===");
        queryAll();
        
        jdbcTemplate.update(insert_sql, id,name,email);//有可能因为主键冲突异常
    }
    
    public void queryAll(){
        List<Map<String, Object>> list = jdbcTemplate.queryForList(query_sql);
        
        for(Map<String, Object> map:list){
            System.out.println(map);
        }
    }
}
  • 在类上面注解了@Transactional,意思是这个类的所有方法交给spring事务管理。而该注解也可以加到方法上,则只有该方法被spring事务管理。

4.运行配置

OK,上面的基本配置都有了,数据库也有了,事务管理也有了,那么只需要总的运行配置了。

如下,代码清单6:

package wang.conge.springdemo.transaction.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({
    DataSourceConfig.class,
    DBCommonConfig.class
})
@ComponentScan("wang.conge.springdemo.transaction.service")
public class AppConfig {
    
}

运行,代码清单7:

package wang.conge.springdemo.transaction;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import wang.conge.springdemo.transaction.config.AppConfig;
import wang.conge.springdemo.transaction.service.UserDao;

public class AppStart {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

        UserDao myService = applicationContext.getBean(UserDao.class);

        try {
            System.out.println("执行SQL前结果:===");
            myService.queryAll();

            myService.testInsert(2, "wow", "wow@163.com");// 主键冲突,数据回滚
        } catch (Exception e) {
            System.out.println(e);
        }

        System.out.println("异常回滚SQL后结果:===");
        myService.queryAll();
    }

}

哦,还少一个pom文件,代码清单8:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>
<!-- spring -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
</dependency>

5.运行结果

OK,基本上整个DEMO就结束了,运行结果也比较简单,但是也表达了事务性,雨果遇到异常则会回滚。

执行SQL前结果:===
{ID=1, NAME=kaka, EMAIL=kaka@qq.com}
{ID=2, NAME=alex, EMAIL=alex@163.com}
{ID=3, NAME=lucy, EMAIL=lucy@gmail.com}

执行正常SQL后结果:===
{ID=1, NAME=kakanew, EMAIL=kaka@qq.com}
{ID=2, NAME=alex, EMAIL=alex@163.com}
{ID=3, NAME=lucy, EMAIL=lucy@gmail.com}

信息: SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana]
org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO users(id,name,email) VALUES (?, ?,?)]; Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.USERS(ID)"; SQL statement:
INSERT INTO users(id,name,email) VALUES (?, ?,?) [23505-191]; nested exception is org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.USERS(ID)"; SQL statement:
INSERT INTO users(id,name,email) VALUES (?, ?,?) [23505-191]

异常回滚SQL后结果:===
{ID=1, NAME=kaka, EMAIL=kaka@qq.com}
{ID=2, NAME=alex, EMAIL=alex@163.com}
{ID=3, NAME=lucy, EMAIL=lucy@gmail.com}

© 著作权归作者所有

共有 人打赏支持
haoran_10
粉丝 25
博文 88
码字总数 80846
作品 0
杭州
程序员
私信 提问
Spring编程式和声明式事务实例讲解

Java面试通关手册(Java学习指南):https://github.com/Snailclimb/JavaGuide 历史回顾: 可能是最漂亮的Spring事务管理详解 Spring事务管理 Spring支持两种方式的事务管理: 编程式事务管理...

snailclimb
05/23
0
0
Spring 声明式注解事务实现机制

Spring中注解事务实现机制 在使用@Transactional 注解管理事务时步骤很简单。但是如果对@Transactional理解不够透彻,很容易出现事务不起作用的情况。所以,在对@Transactional的实现机制要有...

狂奔的熊二
09/21
0
0
Spring的事务管理实现原理初探

这里主要是通过分析部分源码进行剖析Spring事务管理的实现原理。 再分析源码前,现从理论上大概分析哈: 纯JDBC操作数据库的基本步骤: 1. 获取连接 Connection conn = DriverManager.getCon...

rockypeng
2014/01/19
0
0
SpringMVC+Spring+Mybatis+Maven

使用IDE导入maven项目,修改配置,添加依赖 修改web.xml 添加resources目录以及test目录 目录设置为 将目录建在src目录下设置为 配置maven的pom.xml 数据库 UserBase.java dao层接口(UserBas...

lambdaλ
08/07
0
0
Spring应用学习——AOP

AOP 1. AOP:即面向切面编程,采用横向抽取机制,取代了传统的继承体系的重复代码问题,如下图所示,性能监控、日志记录等代码围绕业务逻辑代码,而这部分代码是一个高度重复的代码,也就是在...

江左煤郎
11/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Angularjs实现控制器之间通信方式示例

利用angularjs开发项目中,控制器之间的通信,比如参数的传递,数据的传递,都是比较常见的。控制器之间的通信,显得尤为重要。常见的方式有如下两种:一、angular服务的方式;二、基于事件广...

前端攻城老湿
7分钟前
0
0
xshell使用xftp传输文件

12月11日任务 15.4 xshell使用xftp传输文件 15.5 使用pure-ftpd搭建ftp服务 1.xshell使用xftp传输文件 示例一:xshell使用sftp传输文件 新建一个会话 定义为sftp 连接登入 可以get文件,下载...

hhpuppy
10分钟前
0
0
深入解析Vuex实战总结

这篇文章主要介绍了Vuex的初探与实战小结,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。 1.背景 最近在做一个单页面的管理后台项...

前端攻城小牛
11分钟前
1
0
eslint rules 规则

'rules': { "comma-dangle": ["error", "never"], //是否允许对象中出现结尾逗号 "no-cond-assign": 2, //条件语句的条件中不允许出现赋值运算符 "no-console": 2, //不允许出现console语句 ...

agenyun
54分钟前
2
0
类型判断时instanceof和equals的不同用法

接口设计时为了避免序列化的麻烦,将接口定义为参数为map<String,String>类型的接口,但是现在调用时需要转换当前的实体Bean为Map,接口接收方再把Map转换为另一个Bean实体。过程中的需要对类...

wangtx
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部