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. Atitit Gaussian Blur 高斯模糊 的原理and实现and 用途

    Atitit Gaussian Blur 高斯模糊 的原理and实现and 用途 1.1. 高斯模糊 的原理(周边像素的平均值+正态分布的权重1 1.2. 高斯模糊 的用途(磨皮,毛玻璃效果,背景虚化 ...

  2. java多线程 sleep()和wait()的区别

    接触了一些多线程的东西,还是从java入手吧. 相信看这篇文章的朋友都已经知道进程和线程的区别,也都知道了为什么要使用多线程了. 这两个方法主要来源是,sleep用于线程控制,而wait用于线程间的通 ...

  3. salesforce 零基础学习(二十二)Test简单使用

    本篇内容只是本人简单的mark开发中常出现的一些疑问,方便后期项目使用时奠定基础,如果对Test零基础童鞋,欢迎查看Test官方的使用介绍: https://help.salesforce.com/a ...

  4. iOS开发——高级语法篇&继承、实现、依赖、关联、聚合、组合的联系与区别

    继承.实现.依赖.关联.聚合.组合的联系与区别 分别介绍这几种关系: 继承 指的是一个类(称为子类.子接口)继承另外的一个类(称为父类.父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者 ...

  5. WPF入门教程系列八——布局之Grid与UniformGrid(三)

    五. Grid Grid顾名思义就是“网格”,它的子控件被放在一个一个实现定义好的小格子里面,整齐配列. Grid和其他各个Panel比较起来,功能最多也最为复杂.要使用Grid,首先要向RowDef ...

  6. SQLServer查看死锁

    SQLServer查看死锁 if exists ( select * from sys.procedures where name like '%USP_ShowLocks%' ) drop proc ...

  7. Liferay7 BPM门户开发之37: Liferay7下的OSGi Hook集成开发

    hook开发是Liferay客制扩展的一种方式,比插件灵活,即可以扩展liferay门户,也能对原有特性进行更改,Liferay有许多内置的服务,比如用hook甚至可以覆盖Liferay服务. 可作为 ...

  8. SpringAOP之静态代理

    一.SpringAOP: ⒈AOP:Aspect Oriented Programming 面向切面编程, 实现的是核心业务和非核心业务之间的的分离,让核心类只做核心业务,代理类只做非核心业务.  ⒉ ...

  9. C++中如何定义类和对象?

    在C++语言中,对象的类型被称为类,类代表了某一批对象的共性和特征. 类是对象的抽象,而对象是类的具体实例.如同C中的结构体一样,我们要先定义一个结构体,再使用结构体去定义一个变量.同一个结构体可以定 ...

  10. TSql Output 用法

    第一部分:TSql Output 关键字有两种应用场景 1,作为存储过程的参数类型,从存储过程中返回数据 2,返回受 INSERT.UPDATE.DELETE 或 MERGE 语句影响的各行中的信息, ...