`

spring 3 dataSource 事务管理

 
阅读更多

以前在项目中使用spring管理hibernate,配置spring为hibernate提供的事务,注入sessionFactory,开启事务驱动,在类或Service上加入@Transactional(propagation = Propagation.REQUIRED)注解即可,现在在一个项目中,数据访问没使用hibernate,使用的jdbc加连接池,刚开始的时候逻辑比较简单,未使用spring的事务管理,连接池配置如下:

 

<!-- 数据源配置,使用应用内的DBCP数据库连接池 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
          destroy-method="close">
        <!-- Connection Info -->
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>

        <!-- Connection Pooling Info -->
        <property name="maxIdle" value="${dbcp.maxIdle}"/>
        <property name="maxActive" value="${dbcp.maxActive}"/>
        <property name="defaultAutoCommit" value="false"/>
        <property name="timeBetweenEvictionRunsMillis" value="3600000"/>
        <property name="minEvictableIdleTimeMillis" value="3600000"/>
    </bean>

 此时查询都是正常的,在执行insert,update,delete时执行了sql但是数据库记录没有改变,经查证是一个配置项有问题:

 

 

<property name="defaultAutoCommit" value="false"/>

 在代码中我们的Connection没有手动提交,所以不能持久化到数据库,为了省事就在配置文件中配置如下:

<property name="defaultAutoCommit" value="true"/>

 后来随着逻辑的复杂,需要引入事务,所以使用spring的dataSource事务管理,根据spring的官方文档,加入如下配置:

<!-- a PlatformTransactionManager is still required -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- (this dependency is defined somewhere else) -->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="txManager"/>

 在代码中的Service方法上加入注解:@Transactional(propagation = Propagation.REQUIRED)

 测试代码如下:

@Transactional(propagation = Propagation.REQUIRED)
    public void saveLoginInfo(String userName, String dateString, String result) {
        String sql = "INSERT INTO prc_mbl_usr_usg (slsprs_id, lgn_dtm, lgn_sts ) VALUES (" + "'" + userName + "'," + "'" + dateString + "'," + "'" + result + "')";
        logger.info(sql);
        toolsDao.insertUtils(sql);
        int m = 1;
        if (m == 1) {
            throw new RuntimeException();
        }
        toolsDao.insertUtils(sql);
    }

 可是在测试后,发现事务不能回滚,第一次的插入数据每次测试都能插入,不能回滚,

当时很纳闷,究竟是什么原因导致事务不能生效呢?

起初怀疑是事务配置有问题,看了官方文档,google好了好多,发现配置没问题,

在后来耐着性子从头到尾看一下配置文件,并思考一下整个测试方法的执行过程,

然后恍然大悟,发现连接池的配置:

<property name="defaultAutoCommit" value="true"/>

 也就是说jdbc虽然在事务里,但是自动提交了,所以spring事务无法让数据库回滚,把true改为false后,经测试数据库正常回滚!

 

===============================================================================================================================================================================

分割线以上是第一次写这篇文章,下面是后来的修改!

 

上面的文章是错误的,把配置defaultAutoCommit改为false不是数据库回滚了,而是Connection根本没有提交,发现insert,update语句执行之后根本持久化不到数据库;下面是toolsDao类insertUtils的方法:

    //执行插入操作
    public String insertUtils(String sql) {
        {
            Connection con = null;
            try {
                con = getConnection();
            } catch (SQLException e) {
                logger.error("connect failed", e);
            }
            Statement stmt = null;
            if (con != null) {
                try {
                    stmt = con.createStatement();
                } catch (SQLException e3) {
                    logger.error("createStatement create failed", e3);
                }
            }
            assert stmt != null;
            //(2)发送SQL语句到数据库中
            try {
                stmt.executeUpdate(sql);
                return "success";

            } catch (SQLException e4) {
                logger.error("sql error,or no resSet", e4);
            } finally {
                close(null, stmt, con);
            }
        }
        return "failed";
    }

    //获取Connection
    public Connection getConnection() throws SQLException {
        basicDataSource.getInitialSize();
        return basicDataSource.getConnection();
    }

 如上是我执行插入的操作,这里直接使用连接池,从连接池里获取连接,本意是想使用spring的事务进行事务管理,正确的配置了事务,但是没有生效,为什么?

下面是我个人的分析,如有不正确,请指教:

在真正的插入操作时,使用的是Connection,通过Connection获取的Statement,connection的默认提交方式是true,也就是connection会自动提交的,从上面的代码看,每当执行完插入操作后,会关闭Connection,这里不是真正的关闭,起始这里得到的Connection是一个代理对象,这里的close()方法也就是把Connection还给连接池,标记为空闲,供其他请求使用,再还给连接池之前,connection把数据提交到数据库了,spring的事务是无法回滚的;

我尝试着在上面的代码获取到connection后加了一行代码,con.setAutoCommit(false);让connection不自动提交,让spring管理,可是测试结果是数据根本无法持久化到数据库,所以我感觉要使用spring的事务管理数据源,这种代码实现方式是行不通的,所以我在代码中引入了JdbcTemplate:

从新定义一个dao层的基类(测试代码,就不定义dao接口层了,并且在基类里只实现了一个insert方法,如有需要可以自己实现):

public class BaseDao extends JdbcDaoSupport {

    public void insert(String sql) {
        this.getJdbcTemplate().execute(sql);
    }

}

 子类dao:

public class BaseDaoImipl extends BaseDao {
}

 在spring配置文件中的配置:

    <context:annotation-config />
    <!-- 使用annotation 自动注册bean,并保证@Required,@Autowired的属性被注入 -->
    <context:component-scan base-package="com.intel.store"/>

    <!-- enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="txManager"/>

    <!-- a PlatformTransactionManager is still required -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- (this dependency is defined somewhere else) -->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 被事务管理的数据源 -->
    <bean id="baseDao" class="com.intel.store.dao.BaseDao" abstract="true">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 配置继承 -->
    <bean id="baseDaoImpl" class="com.intel.store.dao.BaseDaoImipl" parent="baseDao">
    </bean>

 这里使用基类baseDao是为了提取公共操作,把重复的CRUD封装到基类中,子类只要调用即可;

 

测试代码:

    //junit测试代码
    @Test
    public void testTransaction() {
        System.out.println(AopUtils.isAopProxy(loginServiceImpl));
        System.out.println(loginServiceImpl.getClass().getName());
        loginServiceImpl.saveLoginInfo("2000040", "2013-09-10 00:00:00.000", "2000040|张美霞test");
    }
    
    //service方法中的业务方法
    @Transactional(propagation = Propagation.REQUIRED)
    public void saveLoginInfo(String userName, String dateString, String result) {
        String sql = "INSERT INTO prc_mbl_usr_usg (slsprs_id, lgn_dtm, lgn_sts ) VALUES (" + "'" + userName + "'," + "'" + dateString + "'," + "'" + result + "')";
        logger.info(sql);
        this.baseDaoImpl.insert(sql);

        int m = 0;

//        if (m == 0) {
//            throw new RuntimeException("出错了!");
//        }
        this.baseDaoImpl.insert(sql);
    }

 放开注释,第一次插入的数据正常回滚,不放开注释,两条数据顺利插入到数据库!

分享到:
评论

相关推荐

    Spring动态切换datasource实现mysql多住多从

    Spring支持多个数据源的事务管理,但需要正确配置事务边界,确保跨数据源的事务一致性。 6. **测试与优化**:完成上述配置后,进行充分的测试以确保切换逻辑的正确性。同时,可以根据系统性能监控和调优数据源配置...

    spring中dataSource的配置以及配合IOC的使用

    在Spring框架中,`dataSource`是用于管理数据库连接的核心组件,它是`DataSource`接口的一个实现,通常由Apache的`DBCP`、`C3P0`或HikariCP等库提供。`dataSource`的配置和与IOC(Inversion of Control,控制反转)...

    spring声明式事务管理配置方式

    在Spring框架中,声明式事务管理是实现事务处理的一种高效且灵活的方式,它允许开发者通过在服务层方法上添加特定的注解来控制事务的边界,而无需编写大量的事务管理代码。这种方式使得业务逻辑和事务控制得以分离,...

    实验 spring 声明事务

    实验 "Spring 声明事务" 是 Java 高级编程中的一个重要环节,旨在让学生掌握 Spring 框架中声明式事务管理的配置和使用。在实际应用中,事务管理是确保数据一致性、完整性和可靠性的关键组件。Spring 提供了声明式...

    Spring2.5实现事务管理(本地事务、分布式事务).doc

    Spring 2.5 实现事务管理(本地事务、分布式事务) Spring 框架提供了对事务管理的支持,它可以使得事务的管理变得更加简洁和灵活。事务管理是指在多个操作中维持一致性的机制,它可以确保在多个操作中,如果某个...

    oesoft_spring_datasource

    综上所述,"oesoft_spring_datasource"这个主题涵盖了Spring框架中数据源的配置方法,包括XML、注解和Java配置,以及与之相关的连接池管理和事务处理。了解并熟练掌握这些知识对于任何Spring开发者来说都是非常重要...

    spring_如何管理事务的

    ### Spring如何管理事务 #### 一、Spring事务管理概述 Spring框架为开发者提供了一套强大的事务管理机制,它简化了应用程序中的事务控制逻辑,使得开发人员能够更加专注于业务逻辑的编写,而不是繁琐的事务管理...

    spring事务与数据库操作

    Spring支持两种类型的事务管理:编程式事务管理和声明式事务管理。其中声明式事务管理因其易于使用和维护而被广泛采用。 ##### 1.1 Spring声明式事务介绍 Spring的声明式事务管理是通过配置文件或注解的方式来实现...

    spring声明式事务管理+jdbc+连接池.zip

    本资料包"spring声明式事务管理+jdbc+连接池.zip"显然是针对Spring框架在数据库操作方面的深入学习,特别是如何利用Spring进行声明式事务管理和JDBC操作,以及如何配置和使用数据库连接池。接下来,我们将详细探讨这...

    Spring AOP配置事务方法

    Spring AOP 提供了一种灵活的方式来实现事务管理,通过配置事务特性和事务管理切面来实现事务管理。 配置事务管理切面: 在 Spring AOP 中,事务管理切面是通过 `&lt;aop:config&gt;` 元素来配置的。该元素用于定义一个...

    spring+druid+AtomikosDataSource实现多数据源切换及分布式事务控制

    3. **AtomikosDataSource与分布式事务** Atomikos是著名的JTA(Java Transaction API)实现之一,提供了分布式事务管理的能力。AtomikosDataSource是基于Atomikos实现的XAPool,可以协调跨多个数据源的ACID(原子性...

    spring事务管理

    ### Spring事务管理详解 #### 一、Spring事务管理概述 Spring框架提供了强大的事务管理功能,使得开发者能够更方便地管理应用程序中的事务。Spring事务管理主要包括两种类型:编程式事务管理和声明式事务管理。 -...

    spring声明式事务处理demo

    同时,需要配置数据源(DataSource)和事务管理器(如`DataSourceTransactionManager`或`JpaTransactionManager`),以便Spring知道如何与数据库交互并管理事务。 ```xml &lt;bean id="dataSource" class="org.spring...

    spring ibatis 配置(包括事务管理)

    以下是关于"spring ibatis 配置(包括事务管理)"的详细说明: 1. **引入依赖**:首先,我们需要在项目中添加Spring和iBatis的相关依赖。通常,这会在Maven或Gradle的配置文件中完成,确保引入了正确的版本。 2. *...

    学习Spring笔记_DataSource

    Spring的DataSourceTransactionManager与DataSource配合使用,提供事务管理功能。通过声明式事务管理,可以简化事务控制代码,例如在XML中配置: ```xml &lt;bean id="transactionManager" class="org.spring...

    Spring Boot多数据源(JdbcTemplate)配置与使用

    3. 创建数据源bean:在`Config`类中创建两个`DataSource` bean,并使用`@Primary`注解标记主数据源。例如: ```java @Configuration public class DataSourceConfig { @Bean(name = "primaryDataSource") @...

    spring mvc+hibernate实现事务管理(配置文件版)

    在本项目中,我们需要配置Spring的事务管理器,一般有两种方式:编程式事务管理和声明式事务管理。声明式事务管理更为常见,它通过在服务层的方法上添加@Transactional注解,由Spring自动进行事务的开启、提交或回滚...

    spring 的3种事务配置方式

    本文将详细介绍Spring中的三种事务配置方式:编程式事务管理、声明式事务管理以及基于注解的事务管理。 **1. 编程式事务管理** 编程式事务管理是通过编程的方式手动控制事务的开始、提交、回滚等操作。主要使用`...

    spring基于AOP实现事务

    在Spring框架中,事务管理是核心功能之一,它允许开发者以声明式或编程式的方式处理应用中的事务。本文将深入探讨如何基于AOP(面向切面编程)来实现Spring的事务管理,特别是通过TransactionProxyFactoryBean。让...

    Spring2.0 事务处理

    在IT行业中,Spring框架是Java企业级应用开发的首选框架之一,尤其是在事务管理方面,它提供了强大而灵活的解决方案。Spring 2.0版本在事务处理方面做了许多改进,使得开发者能够更有效地管理应用程序的事务边界。这...

Global site tag (gtag.js) - Google Analytics