Spring入门第二十九课

事务的隔离级别,回滚,只读,过期

当同一个应用程序或者不同应用程序中的多个事务在同一个数据集上并发执行时,可能会出现许多意外的问题。

并发事务所导致的问题可以分为下面三种类型:

-脏读

-不可重复读

-幻读

看代码:

db.properties

jdbc.user=root
jdbc.password=logan123
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring

jdbc.initPoolSize=5
jdbc.maxPoolSize=10

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: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/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <context:component-scan base-package="logan.study.spring.tx"></context:component-scan>

    <!-- 导入资源文件 -->
    <context:property-placeholder location="classpath:db.properties"/>

    <!-- 配置C3P0数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>

        <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
    </bean>

    <!-- 配置Spring的JDBCTemplate -->
    <bean id="jdbcTemplate"
    class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置NamedParameterJdbcTemplate,该对象可以使用具名参数,其没有无参的构造器,所以必须为其构造器指定参数 -->
    <bean id="namedParameterJdbcTemplate"
    class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
        <constructor-arg ref="dataSource"></constructor-arg>
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 启用事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
package logan.study.spring.tx;

public interface BookShopDao {
    //根据书号获取书的单价
    public int findBookPriceIsbn(String isbn);

    //更新书的库存,使书号对应的库存-1
    public void updateBookStock(String isbn);

    public void updateUserAccount(String username,int price);

}
package logan.study.spring.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public int findBookPriceIsbn(String isbn) {
        // TODO Auto-generated method stub
        String sql = "SELECT price FROM book WHERE isbn=?";
        return jdbcTemplate.queryForObject(sql, Integer.class, isbn);
    }

    @Override
    public void updateBookStock(String isbn) {
        // TODO Auto-generated method stub
        //检查书的库存是否足够,若不够,则抛出异常
        String sql2 = "SELECT stock FROM book_stock WHERE isbn = ?";
        int stock = jdbcTemplate.queryForObject(sql2, Integer.class, isbn);
        if(stock == 0){
            throw new BookStockException("库存不足!");
        }
        String sql = "UPDATE book_stock SET stock = stock -1 WHERE isbn = ?";
        jdbcTemplate.update(sql, isbn);

    }

    @Override
    public void updateUserAccount(String username, int price) {
        // TODO Auto-generated method stub
        //检查书的库存是否足够,若不够,则抛出异常
        String sql2 = "SELECT balance FROM account WHERE username = ?";
        int balance = jdbcTemplate.queryForObject(sql2, Integer.class, username);
        if(balance < price){
            throw new UserAccountException("余额不足!");
        }
        String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";
        jdbcTemplate.update(sql, price, username);

    }

}
package logan.study.spring.tx;

public interface BookShopService {

    public void purchase(String username, String isbn);

}
package logan.study.spring.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService {

    @Autowired
    private BookShopDao bookShopDao;

    //添加事务注解
    @Transactional
    @Override
    public void purchase(String username, String isbn) {
        // TODO Auto-generated method stub
        //1.获取书的单价
        int price = bookShopDao.findBookPriceIsbn(isbn);
        //2.更新书的库存
        bookShopDao.updateBookStock(isbn);
        //3.更新用户余额
        bookShopDao.updateUserAccount(username, price);

    }

}
package logan.study.spring.tx;

import java.util.List;

public interface Cashier {
    public void checkout(String username,List<String> isbns);

}
package logan.study.spring.tx;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service("cashier")
public class CashierImpl implements Cashier{

    @Autowired
    private BookShopService bookShopService;

    /**
     * 使用propagation指定事务的传播行为,即当前的事务方法被另外一个事务方法调用时
     * 如何使用事务,默认取值为REQUIRED,即使用调用方法的事务
     * REQUIRES_NEW事务自己的事务,调用事务方法的事务被挂起
     * 使用isolation指定事务的隔离级别,最常用取值为READ_COMMITTED
     * 默认情况下,Spring的声明式事务对所有的运行时异常进行回滚,也可以通过对应的属性进行设置
     * 使用readonly 指定事务为只读,表示这个事务只读取数据单不更新数据,
     * 这样可以帮助数据库引擎优化事务。若真的是一个只读数据库值的方法,应该设置readOnly=true
     * 使用timeout指定强制回滚之前事务可以占用的时间。
     */
    @Transactional(propagation=Propagation.REQUIRES_NEW,
            isolation=Isolation.READ_COMMITTED,
            noRollbackFor={UserAccountException.class})
    @Override
    public void checkout(String username, List<String> isbns) {
        // TODO Auto-generated method stub
        for(String isbn:isbns){
            bookShopService.purchase(username, isbn);
        }

    }

}

当同一个应用程序或者不同应用程序中的多个事务在同一 个数据集上并发执行时,可能会出现许多意外的问题
并发事务所导致的问题可以分为下面三种类型:

-脏读:对于两个事物T1,T2,T1读取了已经被T2更新但还没有被 提交的字段.之后,若T2回滚,T1读取的内容就是临时且无效的.
-不可重复读:对于两个事物T1,T2,T1读取了一个字段,然后T2更 新了该字段.之后,T1再次读取同一个字段,值就不同了.

-幻读:对于两个事物T1,T2,T1从一个表中读取了一个字段,然后 T2在该表中插入了一些新的行.之后,如果T1再次读取同一个表, 就会多出几行.

时间: 2024-11-05 21:46:09

Spring入门第二十九课的相关文章

Spring入门第二十二课

重用切面表达式 我们有的时候在切面里面有多个函数,大部分函数的切入点都是一样的,所以我们可以声明切入点表达式,来重用. package logan.study.aop.impl; public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); } package logan.study.aop.im

Spring入门第二十四课

Spring对JDBC的支持 直接看代码: db.properties jdbc.user=root jdbc.password=logan123 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql://localhost:3306/selective-courses-system jdbc.initPoolSize=5 jdbc.maxPoolSize=10 applicationContext.xml <?xml ve

Spring入门第二十五课

使用具名参数 直接看代码: db.properties jdbc.user=root jdbc.password=logan123 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql://localhost:3306/selective-courses-system jdbc.initPoolSize=5 jdbc.maxPoolSize=10 applicationContext.xml <?xml version=&quo

Spring入门第二十八课

事务的传播行为 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播,例如:方法可能继续在现有事务中运行,也可能开启一个新的事务,并在自己的事务中运行. 事务的传播行为可以由传播属性指定.Spring定义了7中类型的传播行为. 默认的传播行为是REQUIRED 直接看代码: db.properties jdbc.user=root jdbc.password=logan123 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:

Spring入门第二十六课

Spring中的事务管理 事务简介 事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性. 事务就是一系列的动作,他们被当做一个单独的工作单元,这些动作要么全部完成,要么全部不起作用. 事务的四个关键属性(ACID) -原子性(atomicity):事务是一个原子操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用. -一致性(consistency):一旦所有事务动作完成,事务就被提交,数据和资源就处于一种满足业务规则的一致性状态中. -隔离性(is

NeHe OpenGL教程 第二十九课:Blt函数

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十九课:Blt函数 Blitter 函数: 类似于DirectDraw的blit函数,过时的技术,我们有实现了它.它非常的简单,就是把一块纹理贴到另一块纹理上. 这篇文章是有Andreas Lffler所写的,它写了一份原始的教

Spring入门第二十课

返回通知,异常通知,环绕通知 看代码: package logan.study.aop.impl; public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); } package logan.study.aop.impl; import org.springframework.stereotyp

第二十九课:javascript异步处理

大家知道javascript中有多少方法能够实现异步处理吗?setTimeout(),setInterval()是最常用的两个.XMLHttpRequest对象,进行ajax请求时.postMessage()进行跨域操作时.WebWorker创建新的线程时.setImmediate方法(新的setTimeout方法).requestAnimationFrame进行动画操作时.这些东西都有一个共同的特点,就是拥有一个回调函数.有的异步API还提供了相对应的中断API,比如:clearTimeout

第二十九课

第一单元语法部分 用言てしかた(が)ない     てしようがない/てしょうがない是它较为随便的口语表达    多接在表示感情.感觉或者生理现象的形容词或动词的て形后, 表示情不自禁产生某种感情或感觉,连自己都控制不了.主语多为第一人称.“…得不得了,…得很”    例:    1 先生に褒められて.嬉しくて仕方がありません.    2 病気になって遠足に行けなかったのが.残念で仕方がない.    3 この映画は見る度に.涙が出て仕方がない. Nさえ-ば,-. 强调只要该条件具备,后项就会得出某种