Spring事务管理

    springMVC已经越来越流行了。以下是对spring事务的一些个人总结。我们先了解下事务:数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。

  那么在spring框架中怎么使用尼?

  1、dataSource,jdbcTemplate配置(默认已经了解spring)

    <!-- 配置jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 配置数据源 -->
    <!-- 以dataSource方式使用proxool连接池 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" init-method="init" destroy-method="close">
        <property name="name" value="${jdbc.username}" />
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        
        <property name="initialSize" value="${ds.initialSize}" />
        <property name="minIdle" value="${ds.minIdle}" />
        <property name="maxActive" value="${ds.maxActive}" />
        
        <property name="maxWait" value="${ds.maxWait}" />
        <property name="timeBetweenEvictionRunsMillis" value="${ds.timeBetweenEvictionRunsMillis}" />
        <property name="validationQuery" value="SELECT 'x' FROM dual" />
        <property name="connectionProperties" value="oracle.jdbc.ReadTimeout=${oracle.jdbc.ReadTimeout};oracle.net.CONNECT_TIMEOUT=${oracle.net.CONNECT_TIMEOUT}" />
    </bean>

为了方便修改,采取配置文件的形式。

# 数据库类型设置(oracle)
ds.dialect=oracle
# Oracle数据库
jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.username=dreamer
jdbc.password=123qwe
# SQL执行时间超过一定时间则记录为慢SQL
ds.slowSqlMillis=3000
# 慢SQL统计日志输出
ds.logSlowSql=false
# 合并SQL统计
ds.mergeSql=false
# 初始化时建立物理连接的个数
ds.initialSize=1
# 最小连接数
ds.minIdle=1
# 允许最大连接数,超过了这个连接,再有请求时,就排在队列中等候,最大的等待请求数由maximum-new-connections决定 
ds.maxActive=20
# 获取连接时最大等待时间
ds.maxWait=5000
# 检测需要关闭的空闲连接的间隔时间, 单位是毫秒
ds.timeBetweenEvictionRunsMillis=120000
#oracle jdbc驱动socket超时
oracle.jdbc.ReadTimeout=600000
#oracle jdbc建立新连接超时时间
oracle.net.CONNECT_TIMEOUT=6000

然后就是如果简单的操作数据库了。示例代码

public class JdbcDemo {
    @Autowired
    public JdbcTemplate jdbcTemplate;
    
    public void callP(){
        //调用存储过程
        jdbcTemplate.execute("{}", new CallableStatementCallback<String>() {

            @Override
            public String doInCallableStatement(CallableStatement stat)
                    throws SQLException, DataAccessException {
                //填参数
                stat.setString(0, "hello");
                ResultSet rs = stat.executeQuery();
                while( rs.next()){
                    rs.getString(0);
                    //....取值
                }
                return null;
            }
        });
    }
    public void query(){
        //查询
        jdbcTemplate.query("sql", new RowMapper<Object>(){

            @Override
            public Object mapRow(ResultSet rs, int arg1) throws SQLException {
                rs.getString(0);
                //.....
                return null;
            }});
    }
}

上面就是spring操作数据库了。此时就涉及到事务管理。如果使用spring事务管理尼。我们可以通过依赖注入@Transactional来使用提醒两个注意点:

1.只有通过spring方式实例化才有事务。通过new方式实例化将不包含事务
2.当调用的第一个方法有事务时,里面调用的其他方法也将包含在同一事务里面,反之如果第一个方法没有配置事务,方法内部平级调用方法(此方法配置了事务)。事务也将无效。

public class Test {
    @Transactional
    public void delData(){
        //有事务
        delTabA();
        //本身配置事务无效,事务类型与delData()一致
        delTabB();
    }
    public void delTabA(){
        
    }
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void delTabB(){
        
    }
}
class TestDemo{
    @Autowired
    private Test test;
    public void test() {
        //有事务
        test.delData();
        Test test2 = new Test();
        //无事务
        test2.delData();
    }
}

3.当方法中抛出异常时,如果声明了抛出异常,事务是不回滚的。如果抛出异常时未检查的。事务将会回滚。
如果需要回滚需要增加配置@Transactional(rollbackFor=Exception.class)指定异常,可同时配置多个异常

    import org.springframework.transaction.annotation.Transactional;

    public class Test2 {
        //出现异常将不会回滚
        @Transactional
        public void test ()throws Exception{
            throw new Exception();
        }
        //将会回滚
        @Transactional(rollbackFor=Exception.class)
        public void test2()throws Exception{
            throw new Exception();
        }
        //将会回滚
        @Transactional
        public void test3(){
            throw new RuntimeException("例外");
        }

    }

通过依赖注入可以选着注入的事务类型 @Transactional(propagation=Propagation.REQUIRES_NEW)

PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。 
PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。 
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。 
PROPAGATION_NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

上面就是对单个方法进行事务控制。适合需要精细化处理的项目。但但部分项目不需要这么精细。就可以通过配置对某个包下方法进行IOC事务配置。

 

posted @ 2015-03-26 11:37  灵台方寸小道士  阅读(382)  评论(0编辑  收藏  举报