spring的简单入门(四)之事务

1.什么是事务

►事务管理是企业级应用程序开发中必不可少的技术,  用来确保数据的完整性和一致性.
►事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用
►事务的四个关键属性(ACID)
§原子性(atomicity):事务是一个原子操作, 由一系列动作组成. 事务的原子性确保动作要么全部完成要么完全不起作用.
§一致性(consistency):一旦所有事务动作完成, 事务就被提交. 数据和资源就处于一种满足业务规则的一致性状态中.
§隔离性(isolation):可能有许多事务会同时处理相同的数据, 因此每个事物都应该与其他事务隔离开来, 防止数据损坏.
持久性(durability):一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响. 通常情况下, 事务的结果被写到持久化存储器中.

二.事务的传播性,简单的引用

创建maven项目,在pom.xml中加载架包

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cn</groupId>
  <artifactId>spring</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
  <!-- 加载spring的包 -->
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>4.3.12.RELEASE</version>
  	</dependency>
  	
  	<dependency>
  		<groupId>aopalliance</groupId>
  		<artifactId>aopalliance</artifactId>
  		<version>1.0</version>
  	</dependency>
  	<dependency>
  		<groupId>aspectj</groupId>
  		<artifactId>aspectjweaver</artifactId>
  		<version>1.5.3</version>
  	</dependency>
  	<!-- 添加jdbc的架包 -->
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-jdbc</artifactId>
  		<version>4.3.12.RELEASE</version>
  	</dependency>
  		<!-- 加载数据库的架包 -->
  	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>5.1.26</version>
  	</dependency>
  	<!-- 面向切面编程 -->
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-aop</artifactId>
  		<version>4.3.12.RELEASE</version>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-orm</artifactId>
  		<version>4.3.12.RELEASE</version>
  	</dependency>
  	
  	<dependency>
  		<groupId>log4j</groupId>
  		<artifactId>log4j</artifactId>
  		<version>1.2.17</version>
  	</dependency>
  	<dependency>
			<groupId>aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.2</version>
		</dependency>
  </dependencies>
  	
  
</project>
创建连接数据的四要素jdbc.properties文件

url=jdbc:mysql://localhost:3306/news
driverClassName=com.mysql.jdbc.Driver
userName1=root
password=123456

创建spring.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"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.2.xsd
	http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
	http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
	
	">
	<!-- 扫描bean -->
   <context:component-scan base-package="less04.testm"></context:component-scan>
   <context:property-placeholder location="classpath:/less04/jdbc.properties"/>
   <bean id="dataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <property name="url" value="${url}" ></property>
     <property name="username" value="${userName1}" ></property>
     <property name="password" value="${password}" ></property>
     <property name="driverClassName" value="${driverClassName}" ></property>
   </bean>
   <!-- 事务管理器  不再使用jdbc的commit和rollback 必须由事务管理器提供 -->
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource"></property> 
   </bean>
   <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
   	   <property name="dataSource" ref="dataSource"></property> 
   </bean>
   <!-- 定义通知  通知的代码 spring已经实现  -->
   <tx:advice id="myAdvise"  transaction-manager="transactionManager">
	   	<tx:attributes>
	   	    <!-- 
	   	       propagation="REQUIRED" 方法和方法之间父子关系
	   	         REQUIRED 没有事务创建一个事务 有事务使用当前事务
	   	         REQUIRED_NEW 不管父方法是否存在事务 都会新建事务
	   	         SUPPORTS 父方法存在事务 使用当前事务  没有事务 使用jdbc的事务(自动提交)
	   	         NOT_SUPPORTED 不管父方法是否存在事务 都不会使用事务(挂起事务)
	   	         MANDATORY 必须在事务环境下运行 父方法没有事务 抛出异常
	   	           No existing transaction found for transaction marked with propagation 'mandatory'
	   	         NEVER 父方法不能存在 事务 有事务抛出异常   
	   	           Existing transaction found for transaction marked with propagation 'never'
	   	           
	   	           isolation="DEFAULT"隔离级别
	   	           	DEFAULT使用数据库本身的隔离级别ORACLE(读已提交)MYSQL(可重复读)
	   	           	READ_UNCOMMITTED spring实现读未提交(脏读)
	   	           	REA_COMMITTED spring实现读已提交(不重复读+幻读)
	   	           	REPEATABLE_READ spring实现可重复读(幻读)
	   	           	SERIALIZABLE spring实现串行化(已解决)
	   	           	
	   	           	spring事务运行过程中碰到运行时异常自动回滚 非运行时异常不会回滚
	   	           	rollback-for=""指定会自动回滚的非运行时异常
	   	           	no-rollback-for=""指定某些运行时异常抛出时不回滚
	   	           	
	   	           	只读事务(除特定的方法以外其他的业务逻辑方法都不应该操作事务)
	   	           	read-only="true"设置只读事务
	   	           	timeout=""设置超时时间
	   	     -->
	   		<tx:method name="update*" propagation="REQUIRED"/>
	   		<tx:method name="save*" />
	   		<tx:method name="delete*"/>
	   		<tx:method name="*" read-only="true"/>
	   	</tx:attributes>
   </tx:advice>
    <!-- 定义切点 advice-ref引用通知 -->
   <aop:config>
   	<aop:pointcut expression="execution(* less04.testm.dao.*.*(..))  " id="myPoint"/>
    <aop:advisor advice-ref="myAdvise" pointcut-ref="myPoint"/>
   </aop:config>
   
   
</beans>


持久层

package less04.testm.dao;

import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class AcDaoImpl {
	@Autowired
	JdbcTemplate jdbc;
	@Autowired
	BcDaoImpl b;
	public  void updateAminus(int money) throws SQLException{
		//扣钱
		String sql="update mymoney set lostedmoney=lostedmoney-"+money+" where usid=1";
		jdbc.execute(sql);
		
		//加钱
		b.saveBadd(money);
		int i=5/0;
	}
}



package less04.testm.dao;

import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BcDaoImpl {
	@Autowired
	JdbcTemplate jdbc;
	public  void saveBadd(int money) throws SQLException{
		String sql="update mymoney set lostedmoney=lostedmoney+"+money+" where usid=2";
		jdbc.execute(sql);
	}
}

测试main方法
import java.sql.SQLException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import less04.testm.dao.AcDaoImpl;

/**
 * 编程式事务 
 * 声明式事务
 *    xml声明(全局)
 *    注解声明
 */

public class TestTa {
	static AcDaoImpl myMoneyDao;
	static{
		ApplicationContext context = new GenericXmlApplicationContext("classpath:less04/testm/spring.xml");
		myMoneyDao=(AcDaoImpl)context.getBean("acDaoImpl");
	}

	public static void main(String[] args) throws SQLException {
		myMoneyDao.updateAminus(10);
	}
	
}

三.事务的隔离级别

1.什么是事务的隔离级别

事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:

 脏读:一个事务读到另一个事务未提交的更新数据。

    幻读:例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样。

    不可重复读:比方说在同一个事务中先后执行两条一模一样的select语句,期间在此次事务中没有执行过任何DDL语句,但先后得到的结果不一致,这就是不可重复读。

2.Spring支持的隔离级别

1.DEFAULT 使用数据库本身的隔离级别ORACLE(读已提交)MYSQL(可重复读)
2. READ_UNCOMMITTED 读未提交(脏读)最低的隔离级别,一切皆有可能。 spring实现读未提交(脏读)
3.REA_COMMITTED 读已提交,ORACLE默认隔离级别,有幻读以及不可重复读风险 .spring 实现读已提交(不重复读+幻读)
4.REPEATABLE_READ 可重复读,解决不可重复读的隔离级别,但还是有幻读风险.spring实现可重复读(幻读)
5.SERIALIZABLE 串行化,最高隔离级别,杜绝一切隐患,缺点是效率低.spring实现串行化(已解决)

3.事务的回滚

spring事务运行过程中碰到运行时异常自动回滚 非运行时异常不会回滚

rollback-for=""指定会自动回滚的非运行时异常

no-rollback-for=""指定某些运行时异常抛出时不回滚


  timeout=""设置超时时间 超时时间一般在5到20之间

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章