zoukankan      html  css  js  c++  java
  • 【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 根据网上搜索的资料:

      根据默认规则,如果在执行回调方法的过程中抛出了未检查异常,或者显式调用了TransacationStatus.setRollbackOnly() 方法,则回滚事务;如果事务执行完成或者抛出了 checked 类型的异常,则提交事务。

      但是回滚事务,为什么程序直接停止了呢。

      参考

      [1] Spring JDBC事务管理

      [2] 《Spring in Action》

  • 相关阅读:
    matlab中figure 创建图窗窗口
    matlab中imread 从图形文件读取图像
    matlab中imfinfo 有关图形文件的信息
    matlab中bitshift 将位移动指定位数
    matlab中reshape 重构数组
    matlab中find 查找非零元素的索引和值
    比特数
    matlab中fseek 移至文件中的指定位置
    poj 1039 Pipe(几何基础)
    poj 1556 The Doors(线段相交,最短路)
  • 原文地址:https://www.cnblogs.com/xing901022/p/4272420.html
Copyright © 2011-2022 走看看