spring中编程式事务


一、mybatis的事务控制

1、mybatis的事务:JDBC|Manage 默认不会自动提交。
2、spring集成mybatis的事务:事务默认是自动提交。
需要导入mybatis-spring-xxx.jar包 与 spring-tx-xxxx.jar包
本质:将事务交给了spring管理

二、事务

1.事务

1.1.事务概念

		事务:是逻辑上一组操作,要么全都成功,要么全都失败.
		事物目的就是解决【数据不一致】的问题。

1.2.事务特性(ACID)

		原子性:(A)事务不可分割
        一致性(C):事务执行的前后,数据完整性保持一致.
        隔离性(I):一个事务执行的时候,不应该受到其他事务的打扰
        持久性(D):一旦结束,数据就永久的保存到数据库

1.3.事务3类读问题

如果不考虑隔离性,事务由3类读问题

		脏读:一个事务读到另一个事务未提交数据
		不可重复读:一个事务读到另一个事务已经提交数据(update)导致一个事务多次查询结果不一致
		虚读:一个事务读到另一个事务已经提交数据(insert)导致一个事务多次查询结果不一致

事务解决并发操作3类读问题:设置隔离级别
并发访问丢失更新的问题:Java(锁)/数据库(锁)

1.4.事务的隔离级别

设置事务的隔离级别,从某种程度上可以有效解决事务特性引起的3类读问题

        未提交读:   以上情况都有可能发生。
        已提交读:   避免脏读,但不可重复读,虚读是有可能发生。
        可重复读:   避免脏读,不可重复读,但是虚读有可能发生。
        串行的:        避免以上所有情况.    系统吞吐量很低

2.Spring中事务管理

三层架构:web层:Servlet/jsp---->service层—>dao/mapper层
分层开发:事务处在Service层.

2.1.Spring提供事务管理API

2.1.1.PlatformTransactionManager:平台事务管理器.

            commit(TransactionStatus status) 
            getTransaction(TransactionDefinition definition) 
            rollback(TransactionStatus status) 

2.1.2.TransactionDefinition:事务定义

            ISOLation_XXX:                事务隔离级别.
            PROPAGATION_XXX:    事务的传播行为.(不是JDBC中有的,为了解决实际开发问题.)
            Timeout:                              过期时间

2.1.3.TransactionStatus:事务状态

        是否有保存点
        是否一个新的事务
        事务是否已经提交

2.1.4.三者关系

        PlatformTransactionManager通过TransactionDefinition设置事务相关信息管理事务,
        管理事务过程中,产生一些事务状态:状态由TransactionStatus记录.

2.2.API详解

        Spring为不同的持久化框架提供了不同PlatformTransactionManager接口实现
        org.springframework.jdbc.datasource.DataSourceTransactionManager    
        使用Spring JDBC或iBatis 进行持久化数据时使用

        org.springframework.orm.hibernate3.HibernateTransactionManager  
        使用Hibernate3.0版本进行持久化数据时使用
        
        org.springframework.orm.jpa.JpaTransactionManager           
        使用JPA进行持久化时使用
        
        org.springframework.jdo.JdoTransactionManager   
         当持久化机制是Jdo时使用
        
        org.springframework.transaction.jta.JtaTransactionManager
          使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用

二、spring事务的实现

1、手动(编程)事务(演示了解)

接口: DataSourceTransactionManager
事务管理模板类:transactionTemplate

第1步:业务的层的哪些方法需要事务(黑客)
UserInfoServiceImpl1.zz(int from ,int to ,int money);//银行转账业务

@Component
public  class UserInfoServiceImpl1 implements IUserInfoService {
    
    
    @Autowired
    private UserInfoMapper userInfoMapper;
    
    @Autowired
    private  TransactionTemplate transactionTemplate;
    
//    @Autowired
//    public UserInfoServiceImpl1(PlatformTransactionManager transactionManager) {
    
    
//        this.transactionTemplate = new TransactionTemplate(transactionManager);
//    }

    /**
     * 转账业务:旺财(from)转账给来福(to),转money钱
     * 
     * 旺财(from) 更新操作 减money 来福 (to) 更新操作 加money money =200
     * 
     * 
     * zz(1,2,300)
     */

    @Override
    public void zz(int from, int to, int money) {
    
    
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    
    

            protected void doInTransactionWithoutResult(TransactionStatus status) {
    
    
                try {
    
    
                    //转账的操作
                    zzOptional(from, to, money);
                    System.out.println("转账成功");
                } catch (Exception ex) {
    
    
                    System.out.println("转账失败,进行回滚");
                    status.setRollbackOnly();
                }
            }
        });
    }

    private void zzOptional(int from, int to, int money)  throws Exception{
    
    
        
            // 一,==============旺财的钱减少300==============
            // 1.1查询旺财有多少钱
            UserInfo wc = userInfoMapper.selectByPrimaryKey(from);
            System.out.println(wc);
            // 1.2扣旺财有300
            wc.setMoney(wc.getMoney() - money);
            int result = userInfoMapper.updateByPrimaryKey(wc);

            // ==============二,来福的钱增加300==============
            // 1.1查询旺财有多少钱
            UserInfo lf = userInfoMapper.selectByPrimaryKey(to);
            System.out.println(lf);
            // 1.2扣旺财有300
            lf.setMoney(lf.getMoney() + money);
            int result2 = userInfoMapper.updateByPrimaryKey(lf);
            
            //==============最后的结果==============
            if (result > 0 && result2 > 0) {
    
    
                System.out.println("转账成功!!");
            } else {
    
    
                // int a = 10/0;//产生一个异常
                throw new Exception("转账失败");// 产生一个异常
            }
        
    }

}

接口IUserInfoService

package com.cc.service;

public interface IUserInfoService {
    
    
    /*
     * from:转出的账户
     * to:转入的账户
     * money:转的金额
     * 
     */
    public void zz(int from ,int to,int money);
}

第2步:xml中配置事务管理器 (不同的orm框架 事务管理的方式不同)
(orm框架:mybatis,hibernate,jpa,jdbcTemplate…)
创建spring-datasource.xml

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
	<!--1、加载数据库的配置文件  -->
	<context:property-placeholder location="database.properties"/>
	<!-- 2、创建数据源对象实例-->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
	   <property name="driverClassName"  value="${driver}" />
        <property name="url" value="${url}" />
        <property name="username" value="${userName}" />
        <property name="password" value="${password}" />
	</bean>
	<!-- 3、创建sqlSessionFactory实例 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	   <!--1.dataSource -->
	   <property name="dataSource" ref="dataSource"></property>
	   <!-- 2.xml配置文件位置-->
	   <property name="mapperLocations" value="classpath:mapper/*.xml"/>
	   <!-- 3.别名-->
	   <!-- 4.驼峰自定映射 -->
	</bean>
	<!-- 4、指定mapper接口的位置 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	   <property name="basePackage" value="com.cc.mapper"></property>
	</bean>
	
	<!--  开启注解配置-->
	<context:annotation-config/>
	<context:component-scan base-package="com.cc"></context:component-scan>
	
	<!--5、spring针对MyBaits的事务管理器  -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	   <property name="dataSource" ref="dataSource"/>
	</bean>
	
	<!--6、手动事务模板  -->
	<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> 
	   <property name="transactionManager" ref="transactionManager"></property>
	</bean>  
</beans>

第3步:在业务类定义TransatcionTemplate事务模板类
new TransatcionTemplate(事务管理器);

第4步:在需要事务管理的方法中
(就是第一个文件UserInfoServiceImpl1中的代码:)

                transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    
    

                protected void doInTransactionWithoutResult(TransactionStatus status) {
    
    
                    try {
    
    
                        updateOperation1();//持久层操作1   扣二狗子的300
                        updateOperation2();//持久层操作2   增加付自强300
                    } catch (SomeBusinessException ex) {
    
    
                        status.setRollbackOnly();
                    }
                }
            });

第5步:测试,调用业务类的方法

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-datasource.xml")
public class MyBatisSpringTest {
    
    
    
    @Autowired
    private UserInfoMapper userInfoMapper;
    
    @Autowired
    private UserInfoServiceImpl1 UserInfoServiceImpl1;
    
    @Test
    public void whenSelectSuccess() {
    
    
        System.out.println(userInfoMapper.selectByExample(null));
    }
    
    @Test
    public void whenZzSuccess() {
    
    
        UserInfoServiceImpl1.zz(1, 2,100);
    }

}

2、申明式事务(开发)(待续)

猜你喜欢

转载自blog.csdn.net/GanYangBa/article/details/108876779