spring08事务
实现的效果是: 用户在购买股票的时候,钱减少!股票增加!
模拟出现的问题是! 用户在购买股票的时候,钱减少! 股票没有增加!
01.创建对应的数据库
02.创建对应实体类
public class Account { //银行账户 private Integer aid; private double money; private String aname; public Integer getAid() { return aid; } public void setAid(Integer aid) { this.aid = aid; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } public String getAname() { return aname; } public void setAname(String aname) { this.aname = aname; } public Account(Integer aid, double money, String aname) { super(); this.aid = aid; this.money = money; this.aname = aname; } @Override public String toString() { return "Account [aid=" + aid + ", money=" + money + ", aname=" + aname + "]"; } }
public class Stock { //股票 private Integer sid; private Integer amount; private String sname; public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public Integer getAmount() { return amount; } public void setAmount(Integer amount) { this.amount = amount; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public Stock(Integer sid, Integer amount, String sname) { super(); this.sid = sid; this.amount = amount; this.sname = sname; } public Stock() { super(); } @Override public String toString() { return "Stock [sid=" + sid + ", amount=" + amount + ", sname=" + sname + "]"; } }
03.创建对应的dao
public interface StockDao { //股票开户 void openStock(String sName,Integer amount); //增加股票 void updateStock(String sName,Integer amount); }
public interface AccoutDao { //银行开户 void openAccount(String aName,double money); //购买股票 void updateAccount(String aName,double money); }
04.创建对应的service和自定义的异常类
public interface StockService { //股票开户 void openStock(String sName,Integer amount); //银行开户 void openAccount(String aName,double money); /** * 谁花了多少钱 买了 多少股票?? */ void buyStock(String name,double money,Integer amount) throws BuyStockException; }
/** * @Transactional * isolation:事务的隔离级别 * propagation:事务的传播行为 * rollbackFor :需要回滚的异常类! 类型是Class * readOnly:对数据库的操作 只读! 默认false! * timeout:设置与数据库连接的超时时间! 单位是S! 默认值 -1! */ public class StockServiceImpl implements StockService { private StockDao stockDao; private AccoutDao accountDao; //股票开户 @Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED) @Override public void openStock(String sName, Integer amount) { stockDao.openStock(sName, amount); } //银行开户 @Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED) @Override public void openAccount(String aName, double money) { accountDao.openAccount(aName, money); } /** * 谁花了多少钱 买了 多少股票?? * * 01.减钱 * 02.加股 * @throws BuyStockException */ @Transactional(rollbackFor=BuyStockException.class,isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED) @Override public void buyStock(String name, double money, Integer amount) throws BuyStockException { //银行账户减钱 accountDao.updateAccount(name, money); if(1==1){ //模拟异常 throw new BuyStockException("!!!购买股票失败......."); } stockDao.updateStock(name, amount); } public StockDao getStockDao() { return stockDao; } public void setStockDao(StockDao stockDao) { this.stockDao = stockDao; } public AccoutDao getAccountDao() { return accountDao; } public void setAccountDao(AccoutDao accountDao) { this.accountDao = accountDao; } }
/** * 自定义异常类 */ public class BuyStockException extends Exception { public BuyStockException(String msg){ super(msg); } }
05.创建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:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <!-- 01.spring默认的数据源 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///spring"/> <property name="username" value="t11"/> <property name="password" value="t11"/> </bean> --> <!-- 02.dbcp数据源 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///spring"/> <property name="username" value="t11"/> <property name="password" value="t11"/> </bean>--> <!-- 加载配置文件 数据库需要的4要素 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 03.c3p0数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.userName}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 配置stockDao --> <bean id="stockDao" class="cn.bdqn.dao.impl.StockDaoImpl" p:dataSource-ref="dataSource"/> <!-- 配置accountDao --> <bean id="accountDao" class="cn.bdqn.dao.impl.AccountDaoImpl" p:dataSource-ref="dataSource"/> <!-- 配置stockService --> <bean id="stockService" class="cn.bdqn.service.impl.StockServiceImpl" p:accountDao-ref="accountDao" p:stockDao-ref="stockDao"/> <!-- ==================================事务的配置=========================================--> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 03.使用注解管理事务 --> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- 01.使用代理工厂管理事务 --> <!-- <bean id="serviceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager" ref="transactionManager"/>绑定事务管理器 <property name="target" ref="stockService"/> 声明需要代理的bean <property name="transactionAttributes"> <props>在指定的切入点上配置事务属性 <prop key="open*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop> -:发生异常回滚 +:发生异常提交 <prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED,-BuyStockException</prop> </props> </property> </bean> --> <!-- 02.使用AspectJ来管理事务 切入点的匹配表达式 public * addStock(Stock stock) : * 代表匹配所有的返回值类型 public void *(Stock stock) : * 代表匹配所有没有返回值的方法 public void addStock(..) : .. 匹配所有的参数以及类型 * cn.bdqn.service.*.*(..) : 匹配cn.bdqn.service包下所有类的所有方法 * cn.bdqn.service..*(..) : 匹配cn.bdqn.service包以及子包下所有类的所有方法 * *..service.*.*(..) : 匹配包名有service的包下所有类的所有方法 !!常用!! --> <!-- <tx:advice id="txAdvice" transaction-manager="transactionManager">绑定事务管理器 在连接点的方法上进行事务的属性配置 <tx:attributes> <tx:method name="open*" isolation="DEFAULT" propagation="REQUIRED"/> <tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED" rollback-for="BuyStockException"/> </tx:attributes> </tx:advice> 指定切入点 <aop:config> <aop:pointcut expression="execution(* *..service.*.*(..))" id="myPoint"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPoint"/> </aop:config> --> </beans>
06.创建对应的测试类
public class StockTest { public static void main(String[] args) throws BuyStockException { ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml"); StockService service=(StockService) context.getBean("stockService"); //service.openAccount("小猪", 5000);service.openStock("小猪", 20); service.buyStock("小猪", 250, 1); } // 01.使用代理工厂 管理事务 @Test public void testProxy() throws BuyStockException{ ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml"); StockService service=(StockService) context.getBean("serviceProxy"); service.buyStock("小猪", 250, 1); } // 02.使用AspectJ 和注解 @Test public void testAop() throws BuyStockException{ ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml"); StockService service=(StockService) context.getBean("stockService"); service.buyStock("小猪", 250, 1); } }
public class ReadeMe { /** * 事务:一个或者一组sql语句来完成一个功能! * 事务具有的四个特性: ACID特性! * 01.原子性:一个事物都是一个不可分割的单位!所有的操作 要么都执行,要么都不执行! * 02.一致性:事务必须是数据库从一个一致性的状态到达另一个一致性的状态! * 03.隔离性:一个事务的执行不会被其他的事务干扰!事务之间相互独立! * 04.持久性:事务一旦被提交!这个操作对数据库来说是永久性的! * * * Spring的事务管理: * 事务本事是数据库中的概念! 按理说应该在数据访问层(dao)! * * 绝大多数的情况下,我们是把事务 提升到 业务逻辑层! * 01.使用spring的事务代理工厂 来 管理事务! * 02.使用spring的注解 来 管理事务! 常用 * 03.使用AspectJ的AOP配置 来 管理事务! 常用 * * 需要掌握的两个属性名: * * isolation:事务的隔离级别! * 01.default:采用数据库默认的事务隔离级别 * 001.mysql ---》repeatable-read * 002.oracle---》read_committed * 02. repeatable-read:可重复读取!解决了脏读,不可重复读,没解决幻读! * 03. read_committed:读已提交! 解决了脏读,没解决不可重复读,幻读! * 04. read_uncommitted:读未提交!什么都没有解决! * 05. serializable:串行化!级别最高!效率最低!不存在并发的问题! * * * propagation: 事务的传播行为:一共7中方式! * 01.required:是spring默认的事务传播行为! * 指定的方法必须在事务中执行!如果没有事务,则会自动创建一个事务! * 02.supports:有事务就在事务环境下执行,没有事务就直接执行! * 03.mandatory: * 指定的方法必须在事务中执行!如果没有事务,则抛出异常! * 04.requires_new:总是新创建一个事务! * 如果当前方法存在事务,则把当前的事务挂起,直到新创建的事务执行完毕后执行! * 05.not_supported:指定的方法不能在事务中执行!如果当前方法存在事务,则把当前的事务挂起! * 06.never:指定的方法不能在事务中执行!如果当前方法存在事务,则抛出异常! * 07.nested:指定的方法必须在事务内执行! * 如果执行的方法没有事务,则会创建一个事务! * 如果执行的方法没有事务,则会嵌套执行! * * timeout_default:定义了事务默认的超时时间! * * * Spring事务管理的接口:PlatformTransactionManager * 常用的两个实现类: * 01.使用jdbc和MyBatis时 使用DataSourceTrancationManager * 02.使用hibernate时 使用HibernateTrancationManager * * Spring事务回滚的方式: * 默认的回滚方式--》发生运行时异常回滚!发送受查异常时提交! * 受查异常肯定需要我们手动的设置回滚方式! * 运行时异常严重!一旦发生,JVM中止执行! * * 实现自定义异常类!RuntimeException --> Exception ---> Throwable * */ }