文档章节

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

haoran_10
 haoran_10
发布于 2016/07/15 16:44
字数 1022
阅读 14
收藏 0
点赞 0
评论 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

Spring编程式和声明式事务

1.编程式事务 1.1 编程式和声明式事务的区别 Spring提供了对编程式事务和声明式事务的支持,编程式事务允许用户在代码中精确定义事务的边界,而声明式事务(基于AOP)有助于用户将操作与事务...

梨加橙 ⋅ 前天 ⋅ 0

@Transaction必知必会

1. Spring事务的基本原理 事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式...

maskwang520 ⋅ 04/15 ⋅ 0

spring事务和jdbc事务

Spring事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获取...

TonyStarkSir ⋅ 04/16 ⋅ 0

IOC/AOP工具 - jBeanBox

jBeanBox是一个微形但功能较齐全的IOC/AOP工具适用于JAVA7+,利用了Java的初始化块实现的Java配置代替XML。jBeanBox采用Apache License 2.0开源协议。 其他一些IOC/AOP框架的问题: 1)Sprin...

yong9981 ⋅ 2016/07/25 ⋅ 14

spring梳理(二) 基于注解的方式注册bean

我们知道,如果想要将bean交由spring容器管理,就需要首先将bean注册在spring容器中,而bean可以通过xml或者注解的方式进行注册,基于xml的配置一般是通过、等xml标签进行配置,然后由sprin...

wyn_lin ⋅ 05/25 ⋅ 0

java利用AOP 实现操作日志记录(一)

除springMvc外需要引入@Aspect注解依赖: 定义切面类: 切面类可根据业务要求自行添加逻辑 在spring的容器xml中添加配置: 此处有个注意点:网上说利用AOP无法拦截controller层,经测试,需要...

晓泊 ⋅ 05/08 ⋅ 0

Spring 中常用的两种事务配置方式以及事务的传播性、隔离级别

一、注解式事务 1、注解式事务在平时的开发中使用的挺多,工作的两个公司中看到很多项目使用了这种方式,下面看看具体的配置demo。 2、事务配置实例 (1)、spring+mybatis 事务配置 (2)、...

哲别0 ⋅ 04/20 ⋅ 0

Spring Boot 注解(1)

启动类注解 @SpringBootApplication 使用@SpringbootApplication注解 可以解决根类或者配置类(我自己的说法,就是main所在类)头上注解过多的问题,一个@SpringbootApplication相当于@Conf...

细节探索者 ⋅ 今天 ⋅ 0

SpringBoot 自动开启事务原理

1,TransactionAutoConfiguration ①,这是SpringBoot 的事务注解自动配置类,位于spring-boot-autoconfigure jar下。 ②,@ConditionalOnClass(PlatformTransactionManager.class) 通过这一......

暗中观察 ⋅ 05/27 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

用SQL命令查看Mysql数据库大小

要想知道每个数据库的大小的话,步骤如下: 1、进入information_schema 数据库(存放了其他的数据库的信息) use information_schema; 2、查询所有数据的大小: select concat(round(sum(da...

源哥L ⋅ 41分钟前 ⋅ 0

两个小实验简单介绍@Scope("prototype")

实验一 首先有如下代码(其中@RestController的作用相当于@Controller+@Responsebody,可忽略) @RestController//@Scope("prototype")public class TestController { @RequestMap...

kalnkaya ⋅ 46分钟前 ⋅ 0

php-fpm的pool&php-fpm慢执行日志&open_basedir&php-fpm进程管理

12.21 php-fpm的pool pool是PHP-fpm的资源池,如果多个站点共用一个pool,则可能造成资源池中的资源耗尽,最终访问网站时出现502。 为了解决上述问题,我们可以配置多个pool,不同的站点使用...

影夜Linux ⋅ 55分钟前 ⋅ 0

微服务 WildFly Swarm 管理

Expose Application Metrics and Information 要公开关于我们的微服务的有用信息,我们需要做的就是将监视器模块添加到我们的pom.xml中: 这将使在管理和监视功能得到实现。从监控角度来看,...

woshixin ⋅ 56分钟前 ⋅ 0

java连接 mongo伪集群部署遇到的坑

部署mongo伪集群 #创建mongo数据存放文件地址mkdir -p /usr/local/config1/datamkdir -p /usr/local/config2/data mkdir -p /usr/local/config3/data mkdir -p /usr/local/config1/l......

努力爬坑人 ⋅ 56分钟前 ⋅ 0

React Native & Weex 区别

JS引擎 Weex使用V8, React native使用JSCore JS开发框架 ( Js Framework ) Weex基于vue.js(2W+ star)。小巧轻量的前端开发框架,组件化,数据绑定,2.0引入virtual dom。 ReactNative使用...

东东笔记 ⋅ 今天 ⋅ 1

UIkit 分页组件动态加载简单实现

1. 问题描述 使用过UIkit分页组件的都清楚,UIkit的分页不能动态刷新数据,也就是不能在点击下一页的时候,动态从后台加载数据,并且刷新页数以及该页数上的数据,下面是一个简单实现,没有做...

影狼 ⋅ 今天 ⋅ 0

Mobx入门之三:Provider && inject

上一节中<App/>组件传递状态temperatures给children -- <TemperatureInput />,如果组建是一个tree, 那么属性的传递则会非常繁琐。redux使用Provider给子组件提供store, connect将子组件和s...

pengqinmm ⋅ 今天 ⋅ 0

魔兽世界 7.0版本 S23/S24/S25全职业普通+精锐套

  死亡骑士   (联盟)   (部落)   (精锐)   恶魔猎手   (联盟)   (部落)   (精锐)   德鲁伊   (联盟)   (部落)   (精锐)   猎人   (联盟) ...

wangchen1999 ⋅ 今天 ⋅ 0

maven顶级pom和子pom的版本号批量修改

当一个版本发布,新起一个版本时,我们只需要手动修改一下项目中pom.xml的版本号就可以了。但是如果这个maven项目有很多的子模块项目,那么一个个手动的去改就显得费时费力又繁琐了。还好,m...

ArlenXu ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部