• 使用Spring框架下的完成对事务的操作


    上一章节,我使用了Spring的JDBCTemplate完成了对数据库的操作。但是在一般的情况下,我们对数据库操作时都需要进行事务管理的操作,防止数据库中的数据出现读取到错误提交的数据,如A转账给B,A扣款了,B没有收到款(脏读)等问题。

    事务需要满足4大特性:

      1. 原子性  完成对数据的修改 要么一起执行,要么一起不执行 强调整体
      2. 一致性  存储的数据约束应该一致
      3. 隔离性  防止冲突 并发的事务是相互隔离 不互相影响的
      4. 持久性  确保已经提交的事务内容不丢失

    涉及:Mysql5.7,Eclipse javaEE,Spring3.2,JDK1.7

    此处使用的练习案例是转账。实现A对B进行转账,如果期间出现了异常则事务回滚。

    首先,需要创建一个表 这里我们就只用到用户名和账内金额两个字段即可

    CREATE TABLE `transfer` (
      `username` varchar(15) DEFAULT NULL,
      `money` int(10) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
     
    insert into transfer (`username`, money) value ('pp', 10000);
    insert into transfer (`username`, money) value ('qq', 10000);
     

    在其中存储两个用户,设定账户都为10000。

     

    在java中创建一个项目,导入相应的包(除了Spring必要包外 tx事务处理包,orm包,jdbc包,mysql驱动包,c3p0等)

    Dao类

    package com.hpp.dao;
    
    public interface TransferDao {
    	public void in(String inner, Integer money);
    	public void out(String outer, Integer money);
    }
    
    
    Dao实现类
    package com.hpp.dao.impl;
    
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
    
    import com.hpp.dao.TransferDao;
    
    //需要继承JdbcDaoSupport 其中有dataSource变量 在xml文件中注入数据源
    public class TransferDaoImpl extends JdbcDaoSupport implements TransferDao{
    
    	@Override
    	public void in(String inner, Integer money) {
    		this.getJdbcTemplate().update("update transfer set money=money-? where username=? ",
    				money,inner);
    	}
    
    	@Override
    	public void out(String outer, Integer money) {
    		this.getJdbcTemplate().update("update transfer set money=money+? where username=? ",
    				money,outer);
    	}
    }


    Service类

    package com.hpp.service;
    
    public interface TransferService {
    	void transfer(String outer, String inner, Integer money);
    }
    Service实现类
    package com.hpp.service.impl;
    
    import com.hpp.dao.TransferDao;
    import com.hpp.service.TransferService;
    
    public class TransferServiceImpl implements TransferService{
    
    	private TransferDao transferDao;
    	public void setTransferDao(TransferDao transferDao) {
    		this.transferDao = transferDao;
    	}
    	
    	@Override
    	public void transfer(final String outer, final String inner, final Integer money) {
    		transferDao.in(outer, money);
    //		手动设置的异常
    //		int i = 1/0;
    		transferDao.out(inner, money);
    	}
    	
    }

    JdbcInfo.properties文件,此处用到xml文件加载数据库参数,让数据库参数可配置

    jdbc.driverClass=com.mysql.jdbc.Driver
    jdbc.jdbcUrl=jdbc:mysql://127.0.0.1:3306/mydb
    jdbc.user=root
    jdbc.password=8469

    Spring配置 applicationContext.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:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans 
           					   http://www.springframework.org/schema/beans/spring-beans.xsd
           					   http://www.springframework.org/schema/aop
           					   http://www.springframework.org/schema/aop/spring-aop.xsd
           					   http://www.springframework.org/schema/context 
           					   http://www.springframework.org/schema/context/spring-context.xsd
           					   http://www.springframework.org/schema/tx
           					   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    	<!-- 读取properties文件 -->
    	<context:property-placeholder location="classpath:com/hpp/properties/JdbcInfo.properties"/>
    	<!-- 加载数据源 -->
    	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    		<property name="driverClass" value="${jdbc.driverClass}"></property>
    		<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
    		<property name="user" value="${jdbc.user}"></property>
    		<property name="password" value="${jdbc.password}"></property>
    	</bean>
    	<bean id="transferDao" class="com.hpp.dao.impl.TransferDaoImpl">
    		<property name="dataSource" ref="dataSource"></property>
    	</bean>
    	
    	<bean id="transferService" class="com.hpp.service.impl.TransferServiceImpl">
    		<property name="transferDao" ref="transferDao"></property>
    	</bean>
    	
    	<!-- 事务管理器 -->
    	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource"></property>
    	</bean>
    	<!-- 事务通知 -->
    	<tx:advice id="txAdvice" transaction-manager="txManager">
    		<tx:attributes>
    			<!-- 
    				对指定方法进行事务管理
    				propagation 取值:
    				REQUIRED为默认值 支持当前事务,A如果有事务,B将使用该事务;如果A没有事务,B将创建一个新的事务
    			-->            
    			<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
    		</tx:attributes>
    	</tx:advice>
    	<!-- AOP编程 -->
    	<aop:config>
    		<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.hpp.service..*.*(..))"/>
    	</aop:config>
    </beans>	<tx:advice id="txAdvice" transaction-manager="txManager">
    		<tx:attributes>
    			<!-- 
    				对指定方法进行事务管理
    				propagation 取值:
    				REQUIRED为默认值 支持当前事务,A如果有事务,B将使用该事务;如果A没有事务,B将创建一个新的事务
    			-->            
    			<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
    		</tx:attributes>
    	</tx:advice>
    	<!-- AOP编程 -->
    	<aop:config>
    		<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.hpp.service..*.*(..))"/>
    	</aop:config>
    </beans>

    测试类

    package com.hpp;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.hpp.service.TransferService;
    
    public class TestTransfer {
    	@Test
    	public void test1() {
    		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    		TransferService transferService = (TransferService) applicationContext.getBean("transferService");
    		transferService.transfer("pp", "qq", 1000);
    	}
    }

    当没有异常发生时,转账操作事务可以正常提交,当其中出现了异常,事务会回滚。此处我使用整数除以零来形成一个异常进行测试。

    刚接触内容较浅显,主要是想让自己在将来使用的时候有这方面的印象,因此记下此学习记录。如有错误以及需要改进的地方 劳烦指出。

  • 相关阅读:
    python协程爬取某网站的老赖数据
    python异步回调顺序?是否加锁?
    go语言循环变量
    使用memory_profiler异常
    安装python性能检测工具line_profiler
    等我!
    pytorch代码跟着写
    Python异常类型总结
    Python项目代码阅读【不断更新】
    夏令营体会
  • 原文地址:https://www.cnblogs.com/runningRookie/p/11108784.html
Copyright © 2020-2023  润新知