Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。 DataSource、 TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为 SessionFactory,TransactionManager的实现为HibernateTransactionManager。

一.事务的4个特性:

原子性:一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做,要么全部做。 一致性:数据不会因为事务的执行而遭到破坏。
隔离性:一个事务的执行,不受其他事务(进程)的干扰。既并发执行的个事务之间互不干扰。
持久性:一个事务一旦提交,它对数据库的改变将是永久的。

二:Spring事务的隔离级别

1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
      另外四个与JDBC的隔离级别相对应
 2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
      这种隔离级别会产生脏读,不可重复读和幻像读。
 3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
 4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
      它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
 5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
      除了防止脏读,不可重复读外,还避免了幻像读。

什么是脏数据,脏读,不可重复读,幻觉读?
 脏读: 指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,
         另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据, 那么另外一
         个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
    
 不可重复读: 指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。
         那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据
         可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
            
 幻觉读: 指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及
         到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,
         以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

三:Spring事务类型详解:

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

四.事务的实现方式:

实现方式共有两种:编码方式;声明式事务管理方式。
基于AOP技术实现的声明式事务管理,实质就是:在方法执行前后进行拦截,然后在目标方法开始之前创建并加入事务,执行完目标方法后根据执行情况提交或回滚事务。
声明式事务管理又有两种方式:基于XML配置文件的方式;另一个是在业务方法上进行@Transactional注解,将事务规则应用到业务逻辑中。

五.实现事务的案例

下面模拟一个用户(Account)用钱来买股票(Stock),当用户出钱买股要是错误,就需要我们的事务了。

源码介绍(Spring框架基本jar包全的情况下):

1.首先我们要用到事务的jar包,我用的是:

spring-tx-4.2.0.RELEASE.jar

2.Account.java

package cn.tx.entity;
/**
* 账户
* @author zhangzong
*
*/
public class Account { private Integer aid;//账户编号 private String aname;//用户姓名 private int balance;//账户金额 public Integer getAid() {
return aid;
} public void setAid(Integer aid) {
this.aid = aid;
} public String getAname() {
return aname;
} public void setAname(String aname) {
this.aname = aname;
} public int getBalance() {
return balance;
} public void setBalance(int balance) {
this.balance = balance;
} }

3.Stock.java

package cn.tx.entity;
/**
* 股票类
* @author zhangzong
*
*/
public class Stock { private Integer sid;//股票编号 private String sname;//股票名称 private int count;//股数 public Integer getSid() {
return sid;
} public void setSid(Integer sid) {
this.sid = sid;
} public String getSname() {
return sname;
} public void setSname(String sname) {
this.sname = sname;
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} }

4.AccountDao.java

package cn.tx.dao;
//账户接口
import cn.tx.entity.Account; public interface AccountDao { /**
* 新增账户
* @param account
* @return
*/
public int createAccount(Account account); /**
* 对账户的操作(钱买股,股收钱)
* @param id 账户的编号
* @param money 发费的钱财
* @param isYesOrNo 是买股,还是收钱
* @return 受影响的行数
*/
public int updateBalance(int id,int money,boolean isYesOrNo); /**
* 根据编号查询余额
* @param id 编号
* @return 余额
*/
public int selectOfBalance(int id); }

5.StockDao.java

package cn.tx.dao;
//股票接口
import cn.tx.entity.Stock; public interface StockDao { /**
* 创建股票
* @param stock 股票对象
* @return 受影响行数
*/
public int createStock(Stock stock); /**
* 对股票的操作(钱买股,股收钱)
* @param id 股票编号
* @param num 变化的数量
* @param isYesOrNo 是买股,还是收钱
* @return 受影响的行数
*/
public int updateCount(int id,int num,boolean isYesOrNo); }

6.AccountDaoImpl.java

package cn.tx.dao.impl;
//实现了AccountDao接口的实现类
import org.springframework.jdbc.core.support.JdbcDaoSupport; import cn.tx.dao.AccountDao;
import cn.tx.entity.Account;
//JdbcDaoSupport是JDBC数据访问对象的超类
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override
public int createAccount(Account account) {
String sql = "insert into account(aname,balance) values(?,?)";
int count = this.getJdbcTemplate().update(sql, account.getAname(),
account.getBalance());
return count;
} @Override
public int updateBalance(int id, int money, boolean isBuyOrNot) {
String sql = null;
// isBuyOrNot 为真,金额减少
if (isBuyOrNot) {
sql = "update account set balance=balance-? where aid=?";
} else {
sql = "update account set balance=balance+? where aid=?";
}
int count = this.getJdbcTemplate().update(sql, money, id);
return count;
} @Override
public int selectOfBalance(int id) {
String sql = "select balance from account where aid=?";
Double money = this.getJdbcTemplate().queryForObject(sql,
new Object[] { id }, Double.class);
return money.intValue(); } }

7.StockDaoImpl.java

package cn.tx.dao.impl;
//实现了StockDao接口的实现类
import org.springframework.jdbc.core.support.JdbcDaoSupport; import cn.tx.dao.StockDao;
import cn.tx.entity.Stock;
//JdbcDaoSupport是JDBC数据访问对象的超类
public class StockDaoImpl extends JdbcDaoSupport implements StockDao { @Override
public int createStock(Stock stock) {
String sql="insert into Stock(sname,count) values(?,?)";
int count = this.getJdbcTemplate().update(sql,stock.getSname(),stock.getCount());
return count;
} @Override
public int updateCount(int id, int num, boolean isYesOrNo) {
String sql=null;
if (isYesOrNo) {
sql="update Stock set count+=? where sid=?";
}else {
sql="update Stock set count-=? where sid=?";
}
int count = this.getJdbcTemplate().update(sql,num,id);
return count;
} }

8.AccountService.java

package cn.tx.service;
//用户操作业务接口(用钱买股)
import cn.tx.entity.Account;
import cn.tx.entity.Stock;
import cn.tx.util.StockException; public interface AccountService {
/**
* 新增账户
* @param account
* @return
*/
public int createAccount(Account account); /**
* 对账户的操作(钱买股,股收钱)
* @param id 账户的编号
* @param money 发费的钱财
* @param isYesOrNo 是买股,还是收钱
* @return 收影响的行数
*/
public int updateBalance(int id,int money,boolean isYesOrNo);
/**
* 创建股票
* @param stock 股票对象
* @return 受影响行数
*/
public int createStock(Stock stock);
/**
* 对股票的操作(钱买股,股收钱)
* @param id 股票编号
* @param num 变化的数量
* @param isYesOrNo 是买股,还是收钱
* @return 受影响的行数
*/
public int updateCount(int id,int num,boolean isYesOrNo);
/**
* 购买股票的方法
* @param aid 账户编号
* @param money 发费的金额
* @param sid 股票的编号
* @param num 所买股数
* @throws StockException
*/
public void buyStock(int aid,int money,int sid,int num) throws StockException;
/**
* 根据编号查询余额
* @param id 编号
* @return 余额
*/
public int selectOfBalance(int id);
}

9.AccountServiceImpl.java

package cn.tx.service.impl;
//用户操作实现类 import cn.tx.dao.AccountDao;
import cn.tx.dao.StockDao;
import cn.tx.entity.Account;
import cn.tx.entity.Stock;
import cn.tx.service.AccountService;
import cn.tx.util.StockException; public class AccountServiceImpl implements AccountService { //植入账户接口
private AccountDao adao;
//植入股票接口
private StockDao sdao;
@Override
public int createAccount(Account account) {
// TODO Auto-generated method stub
return adao.createAccount(account);
} @Override
public int updateBalance(int id, int money, boolean isYesOrNo) {
// TODO Auto-generated method stub
return adao.updateBalance(id, money, isYesOrNo);
}
@Override
public int createStock(Stock stock) {
// TODO Auto-generated method stub
return sdao.createStock(stock);
}
@Override
public int updateCount(int id, int num, boolean isYesOrNo) {
// TODO Auto-generated method stub
return sdao.updateCount(id, num, isYesOrNo);
}
@Override
public int selectOfBalance(int id) {
// TODO Auto-generated method stub
return adao.selectOfBalance(id);
} //@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,rollbackFor=StockException.class)
public void buyStock(int aid,int money,int sid,int num) throws StockException{
boolean isBuy=true;//默认为钱买股
//更改账户信息
adao.updateBalance(aid, money, isBuy);
//模拟异常,如果没钱或钱为负数
if(adao.selectOfBalance(aid)<=0){
throw new StockException("异常发生了。。。。。");
}
//更改股票信息
sdao.updateCount(sid, num, isBuy);
} public AccountDao getAdao() {
return adao;
} public void setAdao(AccountDao adao) {
this.adao = adao;
} public StockDao getSdao() {
return sdao;
} public void setSdao(StockDao sdao) {
this.sdao = sdao;
} }

10.StockException.java(制造的一个异常类)

package cn.tx.util;
/**
* 构造一个检查异常
* @author zhangzong
*
*/
public class StockException extends Exception { /**
*
*/
private static final long serialVersionUID = 1L; public StockException() {
super();
} public StockException(String message) {
super(message);
} }

11.applicationContext.xml(Spring的配置文件)---几种事务的实现都在其中

<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" 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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 1.dao -->
<bean id="accountDao" class="cn.tx.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean> <bean id="stockDao" class="cn.tx.dao.impl.StockDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 2.service -->
<bean id="accountService" class="cn.tx.service.impl.AccountServiceImpl">
<property name="adao" ref="accountDao"></property>
<property name="sdao" ref="stockDao"></property>
</bean> <!-- 3.c3p0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean> <!-- 4.注册jdbc属性 -->
<context:property-placeholder location="classpath:jdbc.properties" /> <!--******************************事务配置 ********************************* --> <!-- 注册事务管理器 -->
<bean id="mytxManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- *****************获得事务代理************** --> <!--方法一: 事务自动代理 :此方法要结合注解使用,在AccountServiceImpl的buyStock上 -->
<!--<tx:annotation-driven transaction-manager="mytxManager"/> --> <!-- 方法二:TransactionProxyFactoryBean 生成事务代理 -->
<!-- <bean id="stockServiceProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="accountService"></property>
<property name="transactionManager" ref="mytxManager"></property>
<property name="transactionAttributes">
<props> 四种隔离级别 传播属性 required
<prop key="create*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
<prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED,-StockException
</prop>
</props>
</property>
</bean> --> <!-- 方法三 : aop**************** -->
<tx:advice id="txAdvice" transaction-manager="mytxManager">
<tx:attributes>
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED" />
<tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED"
rollback-for="StockException" />
</tx:attributes>
</tx:advice>
<!-- aop配置 -->
<aop:config>
<aop:pointcut expression="execution(* *..service.*.*(..))"
id="stockPointcut" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="stockPointcut"/>
</aop:config> </beans>

12.jdbc.properties(连接数据库的配置)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc\:mysql\:///mybook
jdbc.username=root
jdbc.password=1234

13.log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c\:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### set log levels - for more verbose logging change 'info' to 'debug' ### log4j.rootLogger=info, stdout

14.MyTest.java

package cn.tx.test;
//测试类
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.tx.entity.Account;
import cn.tx.entity.Stock;
import cn.tx.service.AccountService;
import cn.tx.util.StockException; public class MyTest {
//测试余额
@Test
public void selectOfbalance(){
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
AccountService service = (AccountService) ctx.getBean("accountService");
int balance = service.selectOfBalance(1);
System.out.println(balance);
}
@Test
// 购买股票测试
public void buyStockTest() throws StockException { ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
AccountService service = (AccountService) ctx.getBean("accountService");
// 花200 块 买 2股
service.buyStock(1, 200, 1, 2);
} @Test
// 开户测试
public void addData() {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
AccountService service = (AccountService) ctx.getBean("accountService");
// 银行卡账户
Account account = new Account();
account.setAname("傻瞿亮");
account.setBalance(1000); service.createAccount(account); Stock stock = new Stock();
stock.setSname("脑残教育");
stock.setCount(5); service.createStock(stock);
} }

Spring中的事务的更多相关文章

  1. Spring中的事务管理

    事务简介: 事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性 事务就是一系列的动作,它们被当作一个单独的工作单元.这些动作要么全部完成,要么全部不起作用 事务的四个关键属性( ...

  2. Spring中的事务管理详解

    在这里主要介绍Spring对事务管理的一些理论知识,实战方面参考上一篇博文: http://www.cnblogs.com/longshiyVip/p/5061547.html 1. 事务简介: 事务 ...

  3. Spring,SpringMvc配置常见的坑,注解的使用注意事项,applicationContext.xml和spring.mvc.xml配置注意事项,spring中的事务失效,事务不回滚原因

    1.Spring中的applicationContext.xml配置错误导致的异常 异常信息: org.apache.ibatis.binding.BindingException: Invalid ...

  4. Spring中的事务操作

    事务的特性 原子性:强调事务的不可分割. 一致性:事务的执行的前后数据的完整性保持一致. 隔离性:一个事务执行的过程中,不应该受到其他事务的干扰. 持久性:事务一旦结束,数据就持久化到数据库. 如果不 ...

  5. Spring 中的事务操作、注解、以及 XML 配置

    事务 事务全称叫数据库事务,是数据库并发控制时的基本单位,它是一个操作集合,这些操作要么不执行,要么都执行,不可分割.例如我们的转账这个业务,就需要进行数据库事务的处理. 转账中至少会涉及到两条 SQ ...

  6. Spring中@Transactional事务回滚

    转载: Spring中@Transactional事务回滚 一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部 ...

  7. SSM-Spring-23:概念《Spring中的事务是什么?》

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客会详细讲述Spring中的事务,会展开来用语言解释,用于了解概念和准备面试 事务的概念: 一个或者一组 ...

  8. (转)Spring中的事务操作

    http://blog.csdn.net/yerenyuan_pku/article/details/70024364 事务的回顾 什么是事务 事务是逻辑上的一组操作,组成这组操作的各个逻辑单元,要么 ...

  9. Spring 中的事务

    前言: 之前总结了事务以及数据库中事务相关的知识点,Spring 对于事务做了相应的封装,便于业务开发中使用事务. 项目中使用Spring中的事务首先时基于Mysql数据库中InnoDB 引擎的,如果 ...

随机推荐

  1. java的五种数据类型解析

    不知道大家对java的简单数据类型是否了解,下面针对Java的五种类型简单数据类型表示数字和字符,进行详细的讲解和分析. 一.简单数据类型初始化 在Java语言中,简单数据类型作为类的成员变量声明时自 ...

  2. SqlServer与MySql的一些常用用法的差别

    最近学习了一下mySql,总结一下SqlServer不同一些用法: 操作符优先级以下列表显示了操作符优先级的由低到高的顺序.排列在同一行的操作符具有相同的优先级.:=||, OR, XOR&& ...

  3. WPF入门教程系列十二——依赖属性(二)

    二. 依赖属性的优先级 由于WPF 允许我们可以在多个地方设置依赖属性的值,所以我们就必须要用一个标准来保证值的优先级别.比如下面的例子中,我们在三个地方设置了按钮的背景颜色,那么哪一个设置才会是最终 ...

  4. 自动生成Mapper和Entity工具MybatisGenerator的使用

    新建一个XML文件crmGeneratorConfig.xml,文件具体内容如下.把MybatisGenerator.zip解压出来,把MybatisGenerator文件夹复制到Eclipse安装目 ...

  5. CSS绝对定位的应用

    × 目录 [1]跟随图标 [2]视频提示 [3]下拉菜单[4]边缘对齐[5]星号 [6]全屏适应[7]半区翻图[8]九宫格[9]等高布局[10]整体布局 前面的话 之前的博客文章已经详细介绍过绝对定位 ...

  6. 前端工程师技能之photoshop巧用系列第四篇——图片格式

    × 目录 [1]图片格式 [2]保存设置 前面的话 对于前端来说,图片格式是需要重要掌握的知识.本文是photoshop巧用系列第四篇——图片格式 图片格式 目前在前端的开发中常用的图片格式有jpg. ...

  7. AngularJS的学习--$on、$emit和$broadcast的使用

    AngularJS中的作用域有一个非常有层次和嵌套分明的结构.其中它们都有一个主要的$rootScope(也就说对应的Angular应用或者ng-app),然后其他所有的作用域部分都是继承自这个$ro ...

  8. Greenplum测试环境部署

    1.准备3台主机 本实例是部署实验环境,采用的是Citrix的虚拟化环境,分配了3台RHEL6.4的主机. |------|------| |Master|创建模板后,额外添加20G一块磁盘/dev/ ...

  9. Skeljs – 用于构建响应式网站的前端开发框架

    skelJS 是一个轻量级的前端框架,用于构建响应式站点和应用程序.让设计人员和开发人员可能够使用四个强大的组件:CSS 网格系统,响应式处理程序,CSS 的快捷方式和插件系统. 您可能感兴趣的相关文 ...

  10. 第一篇博文:PHP函数原型中的可选参数写法为什么这么写?

    第一篇,算是开始吧.简单写点儿东西. 刚开始学PHP,在看PHP Manual时遇到一个问题:含可选参数的函数原型中,可选参数的写法看不懂. 例如explode函数 array explode ( s ...