四.事务的兑现格局:

落到实处格局共有三种:编码格局;评释式事务管理格局。
据悉AOP技术完毕的表明式事务管理,实质就是:在艺术执行前后开展阻挠,然后在目的措施先河从前成立并进入工作,执行完目的措施后基于实施情状提交或回滚事务。
表明式事务管理又有二种方法:基于XML配置文件的不二法门;另一个是在作业方法上展开@Transactional注明,将事情规则应用到事情逻辑中。

一.事务的4个特性:

原子性:一个作业中有着对数据库的操作是一个不可分割的操作系列,要么全做,要么全体做。
一致性:数据不会因为作业的施行而境遇损坏。
隔离性:一个业务的履行,不受其余业务(进度)的干扰。既并发执行的个工作之间互不干扰。
持久性:一个工作一旦付出,它对数据库的变动将是永远的。

三:Spring事务类型详解:

PROPAGATION_REQUIRED–支持当前工作,倘若当前没有事情,就新建一个作业。那是最广大的选料。

PROPAGATION_SUPPORTS–匡助当前政工,若是当前从未有过事情,就以非事务形式执行。

PROPAGATION_MANDATORY–接济当前事务,假诺当前失业,就抛出非凡。

PROPAGATION_REQUIRES_NEW–新建事务,若是当前存在业务,把近年来事务挂起。

PROPAGATION_NOT_SUPPORTED–以非事务形式执行操作,假若当前留存业务,就把当前作业挂起。

PROPAGATION_NEVER–以非事务格局执行,若是当前留存业务,则抛出分外。

PROPAGATION_NESTED–假使当前留存工作,则在嵌套事务内执行。假设当前并未事情,则进行与PROPAGATION_REQUIRED类似的操作。

二:Spring事务的隔断级别 

  1. ISOLATION_DEFAULT:
    那是一个PlatfromTransactionManager暗中认可的割裂级别,使用数据库暗许的事情隔离级别.
          此外几个与JDBC的隔断级别相对应
     2. ISOLATION_READ_UNCOMMITTED:
    那是业务最低的隔断级别,它充许令外一个政工能够看来这一个事情未提交的多寡。
          那种隔离级别会时有发生脏读,不可重复读和幻像读。
     3. ISOLATION_READ_COMMITTED:
    保险一个工作修改的多少提交后才能被此外一个作业读取。其余一个业务不可以读取该事务未提交的数据
     4. ISOLATION_REPEATABLE_READ:
    那种事情隔离级别可以幸免脏读,不可重复读。然则可能现身幻像读。
         
    它除了确保一个政工不可以读取另一个政工未提交的数码外,还保险了防止上面的情事时有发生(不可重复读)。
     5. ISOLATION_SE奥德赛IALIZABLE
    那是消费最高代价但是最保证的作业隔离级别。事务被拍卖为种种执行。
          除了幸免脏读,不可重复读外,还防止了幻像读。

怎么是脏数据,脏读,不可重复读,幻觉读?
 脏读:
指当一个政工正在访问数据,并且对数码进行了改动,而这种修改还平素不交到到数据库中,那时,
       
 其它一个工作也访问那几个数目,然后利用了这几个数目。因为这一个数额是还尚无付诸的数目,
那么此外一
       
 个工作读到的那么些数据是脏数据,依照脏数据所做的操作恐怕是不科学的。
    
 不可重复读:
指在一个工作内,数次读同一数据。在那一个业务还未曾完毕时,其它一个业务也走访该同一数据。
       
 那么,在首先个工作中的两遍读数据之间,由于第三个业务的改动,那么首先个业务两遍读到的多少
       
 或许是区其余。那样就生出了在一个工作内两遍读到的数目是差别等的,由此称为是不行重复读。
            
 幻觉读:
指当事务不是单独执行时发出的一种现象,例如首个工作对一个表中的数目开展了改动,那种修改涉及
        
到表中的方方面面数据行。同时,第四个工作也修改那一个表中的数据,那种修改是向表中插入一行新数据。那么,
XML,        
现在就会爆发操作第四个事情的用户发现表中还有没有修改的多寡行,就好象发生了幻觉一样。

Spring配置文件中关于业务配置总是由八个组成部分,分别是DataSource、TransactionManager和代办体制那三片段,无论哪一类配备格局,一般变化的只是代理体制那部分。 DataSource、
TransactionManager那两有些只是会基于数据访问格局有着变动,比如利用Hibernate举行数量访问时,DataSource实际为
SessionFactory,TransactionManager的落到实处为HibernateTransactionManager。

五.贯彻业务的案例

上边模拟一个用户(Account)用钱来买股票(Stock),当用户出钱买股要是一无所能,就要求大家的事体了。

XML 1

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

1.首先大家要用到工作的jar包,小编用的是:

   spring-tx-4.2.0.RELEASE.jar

2.Account.java

XML 2XML 3

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;
    }

}

View Code

3.Stock.java

XML 4XML 5

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;
    }

}

View Code

4.AccountDao.java

XML 6XML 7

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);

}

View Code

5.StockDao.java

XML 8XML 9

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);

}

View Code

6.AccountDaoImpl.java

XML 10XML 11

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();

    }

}

View Code

7.StockDaoImpl.java

XML 12XML 13

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;
    }

}

View Code

8.AccountService.java

XML 14XML 15

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);
}

View Code

9.AccountServiceImpl.java

XML 16XML 17

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;
    }    

}

View Code

10.StockException.java(创立的一个非常类)

XML 18XML 19

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);
    }

}

View Code

11.applicationContext.xml(Spring的安插文件)—两种工作的贯彻都在其间

XML 20XML 21

<?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>

View Code

12.jdbc.properties(连接数据库的安顿)

XML 22XML 23

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

View Code

13.log4j.properties

XML 24XML 25

### 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

View Code

14.MyTest.java

XML 26XML 27

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);
    }

}

View Code

 

相关文章

网站地图xml地图