Spring的事务管理

最后一叨:

    我相信你们首先会发现我的标题变了,不再是系统学习Spring之Spring in action了,因为以前那个标题没有一点意义,标题就是点明一篇文章的中心的.

使自己或者别人能够快速的找到自己想要的信息,所以在以后我都会采用这种直接点题的方法来写标题.还有一个就是以后不要乱叨了,对文章没有什么实质性的

作用,以后写博文会把这些无关紧要信息剔除。

 

索引:

    1.通过四个词来了解Spring的事务

 2.编程式事务管理

    3.声明式事务管理 

知识点:

 

1.通过四个词来了解Spring的事务

  用四个词来描述Spring事务,分别是:原子性(Atomic)一致性(Consistent)隔离性(Isolate)持久性(Durable)

1)原子性(Atomic):  事务是由一个或者多个行为捆绑在一起的工作的单一工作单元.一个或者多个活动同时成功则为成功,若有

一个失败则失败,简单的理解,单一工作单元要么同时工作,要么同时都不工作.

2)一致性(Consistent): 事务结束后,不管事务是成功还是失败都应该与逻辑模型的返回结果一致.

3)隔离性(Isolate): 多个用户操作相同的数据,防止每个用户之间数据相互影响,防止并发数据的读和写.

4)持久性(Durable): 一旦事务提交,事务结果就会持久保存,无论什么样的系统崩溃都无法影响到持久保存后的结果.

Spring不会直接去管理事务,而是代理给特定平台事务的实现,要么是JTA的实现要么是Persistence mechanism的Transaction Manager实现.

特定平台的Transaction Manager实现如下:

在本文中,下面将使用DataSourcetransactionmanager来进行事例的演示.

 

 

2.编程式事务管理

编程式事务管理就是在程序代码中添加事务管理,这是一个入侵式的事务管理,事例如下:

Dao层和Service层接口:

 

public interface SimpleDao {
    //新增用户信息
    int addUser(Map<String,String> map);
}

 

public interface SimpleService {
    //新增用户
    int addUser(Map<String, String> map);
}

Dao层的实现和Service层的实现:

@Repository("simpleDao")
public class SimpleDaoImpl implements SimpleDao {
    @Autowired
    private SimpleJdbcTemplate jdbcTemplate;
    @SuppressWarnings("deprecation")
    @Override
    public int addUser(Map<String, String> map) {
        // TODO Auto-generated method stub
        return jdbcTemplate.update("insert into t_user values(?,?,?)",map.get("id"),map.get("username"),map.get("password"));
    }
}
public class SimpleServiceImpl implements SimpleService {
    @Autowired
    private SimpleDao simpleDao;
    private TransactionTemplate transactionTemplate;
    public TransactionTemplate getTransactionTemplate() {
        return transactionTemplate;
    }
    
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }
    @Override
        public int addUser(final Map< String, String> map) {
            // TODO Auto-generated method stub
            transactionTemplate.execute(new TransactionCallback<Void>(){
                public Void doInTransaction(TransactionStatus txStatus){
                    try{
                         simpleDao.addUser(map);
                    }catch(RuntimeException e){
                        txStatus.setRollbackOnly();
                        System.out.println("回滚成功.");
                        throw e;
                    }
                    return null;
            }
        });
            return 0;
    }
}    

配置文件:

<context:component-scan base-package="com.ricky.zero">
</context:component-scan>

<aop:aspectj-autoproxy/>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/studyspring"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="simpleService" class="com.ricky.zero.service.impl.SimpleServiceImpl">
    <property name="transactionTemplate">
        <bean class="org.springframework.transaction.support.TransactionTemplate">
            <property name="transactionManager"  ref="transactionManager"></property>
        </bean>
    </property>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
    <constructor-arg ref="dataSource"/>
</bean>

从service的实现中可以看出,编程式的事务管理入侵性很强,但是优点也很明确,就是你可以细粒度的控制事务.一般情况下如果你不需要细粒度的去控制

事务,你可以选择下面要讲的非入侵性的声明式的事务管理.

测试下上面的编程式事务管理:

        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        SimpleService simpleService  = (SimpleService)ctx.getBean("simpleService");
        Map<String,String> p = new HashMap<String,String>();
        p.put("id", "1");
        p.put("username", "big");
        p.put("password", "small");
        simpleService.addUser(p);

执行第一次,可以看到数据库中多了一条记录,

若继续在执行此程序,可以预见的是违反了唯一性约束条件,执行后,打印出"回滚成功."并输出异常信息.

得到以上信息说明编程式事务管理成功.

 

   3.声明式事务管理

Dao层接口和Service层接口与上文相同,不在重复.

Dao层实现没有做任何修改,只修改了Service层实现:

@Service("simpleService")
public class SimpleServiceImpl implements SimpleService {
    @Autowired
    private SimpleDao simpleDao;
    @Override
        public int addUser(final Map< String, String> map) {
            // TODO Auto-generated method stub
             int result = simpleDao.addUser(map);
            return result;
    }
}

配置文件:

<context:component-scan base-package="com.ricky.zero">
</context:component-scan>

<aop:aspectj-autoproxy/>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/studyspring"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>

</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
    <constructor-arg ref="dataSource"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED"/>
        <tx:method name="*"  propagation="SUPPORTS"  read-only="true"/>
    </tx:attributes>    
</tx:advice>

<aop:config>
    <aop:advisor advice-ref="txAdvice"  pointcut="execution(* *..SimpleService.*(..))"/>
</aop:config>


测试运行:

        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        SimpleService simpleService  = (SimpleService)ctx.getBean("simpleService");
        Map<String,String> p = new HashMap<String,String>();
        p.put("id", "4");
        p.put("username", "big");
        p.put("password", "small");
        simpleService.addUser(p);

运行结果:

插入成功,这是正确的操作.

修改Service层的实现 :

@Service("simpleService")
public class SimpleServiceImpl implements SimpleService {
    @Autowired
    private SimpleDao simpleDao;
    @Override
        public int addUser(final Map< String, String> map) {
            // TODO Auto-generated method stub
             int result = simpleDao.addUser(map);
             //多执行了一次插入,由于ID相同,肯定会抛异常,如果能正确回滚,则没有一条信息可以插进去.
             simpleDao.addUser(map);
            return result;
    }
}    

修改测试:

        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        SimpleService simpleService  = (SimpleService)ctx.getBean("simpleService");
        Map<String,String> p = new HashMap<String,String>();
        p.put("id", "5");//id由4变成5
        p.put("username", "big");
        p.put("password", "small");
        simpleService.addUser(p);

运行测试:

回滚成功,没有一条id为5的记录.

声明式事务管理除了XML配置的形式还有注解的形式.

修改Service实现:

@Service("simpleService")
@Transactional(propagation = Propagation.SUPPORTS , readOnly = true)
public class SimpleServiceImpl implements SimpleService {
    @Autowired
    private SimpleDao simpleDao;
    @Transactional(propagation = Propagation.REQUIRED , readOnly = false)
    @Override
        public int addUser(final Map< String, String> map) {
            // TODO Auto-generated method stub
             int result = simpleDao.addUser(map);
             //多执行了一次插入,由于ID相同,肯定会抛异常,如果能正确回滚,则没有一条信息可以插进去.
             simpleDao.addUser(map);
            return result;
    }
}    

配置文件:

<context:component-scan base-package="com.ricky.zero">
</context:component-scan>

<aop:aspectj-autoproxy/>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/studyspring"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
    <constructor-arg ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>

测试同上:

注解和XML得到的结果是相同的,至于选择则根据喜好.

 

 

 

 

 

posted @ 2013-04-08 00:53  养家糊口  阅读(411)  评论(0编辑  收藏  举报