【Spring实战】—— 16 基于JDBC持久化的事务管理

前面讲解了基于JDBC驱动的Spring的持久化管理,本篇开始则着重介绍下与事务相关的操作。

通过本文你可以了解到:

  1 Spring 事务管理的机制

  2 基于JDBC持久化的事务管理

  首先看一下Spring的事务管理的机制

  Spring本身并不提供事务管理,它只是把事务管理提交给事务管理器,而事务管理器则有多种实现,常见的就是基于JDBC的、Hibernate的、JPA以及JTA的。

  操作流程可以参考下面的图片:

  其实还有好多种类的事务管理器,这里就不一一列举了。

  下面看一下在基于JDBC持久化的事务管理

  基于JDBC的持久化,其实就是使用JDBC驱动,在利用spring模板的情况下实现的持久化。

  与Hibernate不同的是,它没有一些Session的概念以及实体关联关系等,因此在查询结果的时候,需要手动的进行转换。

  其他的方面来说,还是很简单实用的。

  下面看一下主要的代码实现流程:

  观察上面的实现结构,整个代码在DAO层的实现部分编写,其中包括主要的两个bean,一个是Spring的JDBC模板,一个是事务处理,这两个bean都会依赖于dataSource。

  DAO(data access object)数据访问对象,一般应用架构都会设计这样一层,用于存放于数据库进行交互的代码,以使应用层次化,便于管理和开发。

  因此就好理解下面的配置文件了:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                         http://www.springframework.org/schema/context
                         http://www.springframework.org/schema/context/spring-context-3.0.xsd
                         http://www.springframework.org/schema/tx
                         http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                         http://www.springframework.org/schema/aop
                         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <!-- JDBC数据源配置 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="123qwe"/>
    </bean>
    <!--  配置DAO实现类,注入jdbcTemplate和transactionManager -->
    <bean id="newjdbcdao" class="com.spring.chap6.dao.NewJdbcImpl" >
        <property name="jdbcTemplate" ref="jdbcTemplate" />
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
    <!--  将数据源注入到jdbctemplate中 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--  将数据源注入到transactionManager中 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

  下面是dao的接口部分,仅仅给出了查询所有数据和插入一条数据的例子:

public interface NewJdbc {
    //插入数据
    public void insertPerson(String id,String name,int age);
    //通过ID查询数据
    public void findAllPersons();
}

  下面是重要的部分,查询方法,仅仅通过模板提供了一个模板的使用样例。

  其中query方法含有两个参数。

  一个是查询SQL语句,另一个是转换类(用于把查询结果ResultSet转换成POJO类)。

  而插入数据的方法中,使用了事务管理。

  当执行new Integer("hello!")时,由于字符串无法转换到整型出错,会导致事务回滚,写操作回滚。

  其中的事务处理的源码参考如下,还没看明白,日后慢慢学习:

  源码给出,仅供参考:

    public <T> T execute(TransactionCallback<T> action) throws TransactionException {
        if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
            return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
        }
        else {
            TransactionStatus status = this.transactionManager.getTransaction(this);
            T result;
            try {
                result = action.doInTransaction(status);
            }
            catch (RuntimeException ex) {
                // Transactional code threw application exception -> rollback
                rollbackOnException(status, ex);
                throw ex;
            }
            catch (Error err) {
                // Transactional code threw error -> rollback
                rollbackOnException(status, err);
                throw err;
            }
            catch (Exception ex) {
                // Transactional code threw unexpected exception -> rollback
                rollbackOnException(status, ex);
                throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
            }
            this.transactionManager.commit(status);
            return result;
        }
    }

  下面则是DAO的实现部分的所有代码:

public class NewJdbcImpl extends JdbcDaoSupport implements NewJdbc{
    public DataSourceTransactionManager transactionManager;
    public void setTransactionManager(DataSourceTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }
    /**
     * 插入数据
     */
    public void insertPerson(final String id,final String name,final int age){
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        final JdbcTemplate jdbcTemplate = this.getJdbcTemplate();
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus arg0) {
                //这个方法内部,是一个事务
                jdbcTemplate.update("insert into persons(id,name,age) values (?,?,?)",
                        id,name,age);
                new Integer("hello!");
            }
        });
    }
    /**
     * 查询所有的数据
     */
    public void findAllPersons(){
        List<Person> list = this.getJdbcTemplate().query("select * from persons", new PersonRowMapper());
        for(Person p : list){
            System.out.println("id:"+p.getId()+" name:"+p.getName()+" age:"+p.getAge());
        }
    }
    /**
     * 转换查询结果
     * @author xingoo
     */
    class PersonRowMapper implements RowMapper{
        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            Person person = new Person();
            person.setId(rs.getString(1));
            person.setName(rs.getString(2));
            person.setAge(rs.getInt(3));
            return person;
        }
    }
}

  Person的POJO类:

public class Person {
    private String id;
    private String name;
    private int age;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

  测试时使用的main方法(一直没有使用单元测试,真不专业,习惯下次要改!)

public class test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
        NewJdbc newjdbc = (NewJdbc)ctx.getBean("newjdbcdao");
        newjdbc.insertPerson("005", "xingoo5", 25);
        newjdbc.findAllPersons();
    }
}

  数据库的SQL部分可以参考前一篇。

  【这里遗留了一个问题,当事务失败回滚时,查询语句也无法执行了。难道是因为使用的同一个JdbcTempalte的缘故?这个问题需要看源码探究,暂时记录一下。】

  参考

  [1] Spring JDBC事务管理

  [2] 《Spring in Action》

时间: 2024-10-18 21:48:01

【Spring实战】—— 16 基于JDBC持久化的事务管理的相关文章

Spring基于声明式的事务管理

事务管理 Spring提供了编码式和声明式事务管理的支持. 编码式事务允许用户在代码中精确定义事务的边界,而声明式事务(基于AOP)用助于用户将操作与事务解耦. 选择编码式还是声明式在很大程度上是在细粒度控制和易用性之间权衡. Spring并不直接管理事务,而是提供多种事务管理器,将它们事务管理职责委托给JTA或其他持久化机制所提供的平台相关的事务实现.每个事务管理器都会充当某一特定平台的事务实现的门面,这使得用户在Spring中使用事务时,不用关注事务的实际实现是什么. JDBC事务 <bea

【j2ee spring】7、spring与数据库的连接的操作事务管理

spring与数据库的连接的操作事务管理 1.首先我们的知道spring管理事务的方式有两种 还是一种是以注解的方式 在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚.这个例外是unchecked 如果遇到checked意外就不回滚. 1 让checked例外也回滚:在整个方法前加上 @Transactional(rollb

Spring Boot 中使用 @Transactional 注解配置事务管理

事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP,将具体业务逻辑与事务处理解耦.声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多.声明式事务有两种方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于 @Transactional 注解的方式.本文将着重介绍基于 @Transactional 注解的事务管

谈谈分布式事务之二:基于DTC的分布式事务管理模型[下篇]

[续上篇] 当基于LTM或者KTM的事务提升到基于DTC的分布式事务后,DTC成为了本机所有事务型资源管理器的管理者:此外,当一个事务型操作超出了本机的范 围,出现了跨机器的调用后,本机的DTC需要于被调用者所在机器的DTC进行协助.上级对下级(包括本机DTC对本机所有资源管理器,以及上下级DTC) 的管理得前提是下级在上级那里登记,即事务登记(Transaction Enlist).所有事务参与者,包括所有资源管理器和事务管理器(即DTC)在进行了事务等级完成之后形成了一个树形的层级结构,该结

Java数据库连接——JDBC调用存储过程,事务管理和高级应用

阅读目录 一.JDBC常用的API深入详解及存储过程的调用1.存储过程(Stored Procedure)的介绍2.JDBC调用无参存储过程3.JDBC调用含输入参数存储过程4.JDBC调用含输出参数存储过程二.JDBC的事务管理1.JDBC实现事务管理2.通过代码实现事物的管理三.数据库连接池(dbcp.c3p0)1.dbcp使用步骤2.c3p0使用步骤3.连接池总结四.JDBC的替代产品(Hibernate.Mybatis)1.Commons-dbutils 2.Hibernate简介3.M

Spring与Hibernate整合,实现Hibernate事务管理

1.所需的jar包 连接池/数据库驱动包 Hibernate相关jar Spring 核心包(5个) Spring aop 包(4个) spring-orm-3.2.5.RELEASE.jar                 [spring对hibernate的支持] spring-tx-3.2.5.RELEASE.jar                     [事务相关] 2.配置文件 Product.hbm.xml <?xml version="1.0" encoding=

Spring.NET教程(十六)事务管理(应用篇)

目前有很多种数据访问技术.在.net FCL中,有三类API可以执行事务管理,分别是ADO.NET.企业服务和System.Transactions.其它的数据访问技术,如对象关系映射(object relational mappers)和结果集映射(result-set mapping)等等的应用也很广泛,每种技术也都有自己的事务管理API.事务管理的代码一般是直接和各种事务API绑定在一起的,所以在开发时必须根据所用的具体技术来决定采用哪种API.但是,这种代码与事务API的紧耦合决定了很难

SpringMVC + Spring + MyBatis 学习笔记:SpringMVC和Spring一同工作的时候,AOP事务管理不起作用的解决方法

系统:WIN8.1 数据库:Oracle 11GR2 开发工具:MyEclipse 8.6 框架:Spring3.2.9.SpringMVC3.2.9.MyBatis3.2.8 SpringMVC 的 springmvc.xml文件中 配置扫描包,不要包含 service的注解,Spring 的 配置文件配置包扫描时,不要包含controller的注解,如下所示: Spring MVC的配置文件: <context:component-scan base-package="包路径"

【Spring】16、注解事务 @Transactional

概述 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性.Spring Framework对事务管理提供了一致的抽象,其特点如下: 为不同的事务API提供一致的编程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence API和JDO(Java Data Objects) 支持声明式事务管理,特别是基于注解的声明式事务管理,简单易用 提供比其他事务API如JTA更简单的编程式事务管理