首页 > 代码库 > [原创]java WEB学习笔记109:Spring学习---spring中事物管理
[原创]java WEB学习笔记109:Spring学习---spring中事物管理
博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用
内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系。
本人互联网技术爱好者,互联网技术发烧友
微博:伊直都在0221
QQ:951226918
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1.事务简介
1)事务管理是企业级应用程序开发中必不可少的技术, 用来确保数据的完整性和一致性.
2)事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用
3)事务的四个关键属性(ACID)
① 原子性(atomicity): 事务是一个原子操作, 由一系列动作组成. 事务的原子性确保动作要么全部完成要么完全不起作用.
② 一致性(consistency): 一旦所有事务动作完成, 事务就被提交. 数据和资源就处于一种满足业务规则的一致性状态中.
③ 隔离性(isolation): 可能有许多事务会同时处理相同的数据, 因此每个事物都应该与其他事务隔离开来, 防止数据损坏.
④ 持久性(durability): 一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响. 通常情况下, 事务的结果被写到持久化存储器中.
2.在JDBC中事物的处理
3.spring 中的事物处理
1)作为企业级应用程序框架, Spring 在不同的事务管理 API 之上定义了一个抽象层. 而应用程序开发人员不必了解底层的事务管理 API, 就可以使用 Spring 的事务管理机制.
2)Spring 既支持编程式事务管理, 也支持声明式的事务管理.
3)编程式事务管理: 将事务管理代码嵌入到业务方法中来控制事务的提交和回滚. 在编程式管理事务时, 必须在每个事务操作中包含额外的事务管理代码.
4)声明式事务管理: 大多数情况下比编程式事务管理更好用. 它将事务管理代码从业务方法中分离出来, 以声明的方式来实现事务管理. 事务管理作为一种横切关注点, 可以通过 AOP 方法模块化. Spring 通过 Spring AOP 框架支持声明式事务管理.
5)Spring 从不同的事务管理 API 中抽象了一整套的事务机制. 开发人员不必了解底层的事务 API, 就可以利用这些事务机制. 有了这些事务机制, 事务管理代码就能独立于特定的事务技术了.
6)spring 的核心事务管理抽象是 org.springframework.transaction Interface PlatformTransactionManager 它为事务管理封装了一组独立于技术的方法. 无论使用 Spring 的哪种事务管理策略(编程式或声明式), 事务管理器都是必须的.
4.Spring 中的事务管理器的不同实现
5.实例需求
1)类图
2)代码结构
3)具体代码
1 package com.jason.spring.tx; 2 3 public interface BookShopDao { 4 5 //根据书号获取书的单价 6 public int findBookPirceByIsbn(String isbn); 7 8 //更新书的库存,使对应的书号 - 1 9 public void updateBookStock(String isbn);10 11 //更新用户的账户余额:是username 的balance - price12 public void updateUserAccount(String username, int price);13 14 }
1 package com.jason.spring.tx; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.jdbc.core.JdbcTemplate; 5 import org.springframework.stereotype.Repository; 6 7 @Repository("bookStockImpl") 8 public class BookShopImpl implements BookShopDao{ 9 10 @Autowired11 private JdbcTemplate jdbcTemplate;12 13 @Override14 public int findBookPirceByIsbn(String isbn) {15 String sql = "SELECT price FROM book WHERE isbn = ?";16 return jdbcTemplate.queryForObject(sql, Integer.class, isbn);17 }18 19 @Override20 public void updateBookStock(String isbn) {21 //检查书的库存是否足够,若不够,则抛出异常22 String sql2 = "SELECT stock FROM book_stock WHERE isbn = ?";23 int stock = jdbcTemplate.queryForObject(sql2, Integer.class, isbn);24 if(stock == 0){25 throw new BookStockExceprtion("库存不足!!!");26 }27 28 29 30 String sql = "UPDATE book_stock SET stock = stock -1 WHERE isbn = ?";31 jdbcTemplate.update(sql, isbn);32 33 }34 35 @Override36 public void updateUserAccount(String username, int price) {37 //验证余额是否足够,若不足,则抛出异常38 String sql2 = "SELECT balance FROM account WHERE username = ?";39 int balance = jdbcTemplate.queryForObject(sql2, Integer.class, username);40 if(balance < price){41 throw new UserAccountException("余额不足!!!");42 }43 44 String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";45 jdbcTemplate.update(sql, price, username);46 47 }48 49 }
1 package com.jason.spring.tx;2 3 public interface BookShopService {4 5 public void purchase(String username, String isbn);6 7 }
1 package com.jason.spring.tx; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 import org.springframework.transaction.annotation.Transactional; 6 7 @Service("bookShopService") 8 public class BookShopServiceImpl implements BookShopService{ 9 10 @Autowired11 private BookShopDao bookShopDao;12 13 @Transactional14 public void purchase(String username, String isbn) {15 16 //1.读取书的单价17 int price = bookShopDao.findBookPirceByIsbn(isbn);18 19 //2.更新书的库存20 bookShopDao.updateBookStock(isbn);21 22 //3.更新用户的余额23 bookShopDao.updateUserAccount(username, price);24 25 }26 27 }
1 package com.jason.spring.tx; 2 3 public class BookStockExceprtion extends RuntimeException{ 4 5 public BookStockExceprtion() { 6 super(); 7 // TODO Auto-generated constructor stub 8 } 9 10 public BookStockExceprtion(String message, Throwable cause,11 boolean enableSuppression, boolean writableStackTrace) {12 super(message, cause, enableSuppression, writableStackTrace);13 // TODO Auto-generated constructor stub14 }15 16 public BookStockExceprtion(String message, Throwable cause) {17 super(message, cause);18 // TODO Auto-generated constructor stub19 }20 21 public BookStockExceprtion(String message) {22 super(message);23 // TODO Auto-generated constructor stub24 }25 26 public BookStockExceprtion(Throwable cause) {27 super(cause);28 // TODO Auto-generated constructor stub29 }30 31 32 }
1 package com.jason.spring.tx; 2 3 public class UserAccountException extends RuntimeException{ 4 5 public UserAccountException() { 6 super(); 7 // TODO Auto-generated constructor stub 8 } 9 10 public UserAccountException(String message, Throwable cause,11 boolean enableSuppression, boolean writableStackTrace) {12 super(message, cause, enableSuppression, writableStackTrace);13 // TODO Auto-generated constructor stub14 }15 16 public UserAccountException(String message, Throwable cause) {17 super(message, cause);18 // TODO Auto-generated constructor stub19 }20 21 public UserAccountException(String message) {22 super(message);23 // TODO Auto-generated constructor stub24 }25 26 public UserAccountException(Throwable cause) {27 super(cause);28 // TODO Auto-generated constructor stub29 }30 31 32 }
1 package com.jason.spring.tx; 2 3 import static org.junit.Assert.*; 4 5 import org.junit.Test; 6 import org.springframework.context.ApplicationContext; 7 import org.springframework.context.support.ClassPathXmlApplicationContext; 8 9 public class BookStockImplTest {10 11 private ApplicationContext ctx = null;12 private BookShopDao bookShopDao = null;13 private BookShopService bookShopService = null;14 15 {16 ctx = new ClassPathXmlApplicationContext("application.xml");17 bookShopDao = ctx.getBean(BookShopDao.class);18 bookShopService = ctx.getBean(BookShopService.class);19 20 }21 22 @Test23 public void testFindBookPirceByIsbn() {24 System.out.println(bookShopDao.findBookPirceByIsbn("1001"));25 }26 27 @Test28 public void testUpdateBookStock() {29 bookShopDao.updateBookStock("1001");30 }31 32 @Test33 public void testUpdateUserAccount() {34 bookShopDao.updateUserAccount("tom", 200);35 }36 37 @Test38 public void testBookShopService(){39 bookShopService.purchase("jason", "1001");40 41 42 43 }44 45 }
6.实现声明式事物的步骤
1)在xml文件中,配置管理事物,启用管理事物
1 <!-- 导入资源文件 --> 2 <context:property-placeholder location="classpath:db.properties"/> 3 <!-- 配置c3p0 数据源 --> 4 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 5 <property name="user" value="${jdbc.user}"></property> 6 <property name="password" value="${jdbc.password}"></property> 7 <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> 8 <property name="driverClass" value="${jdbc.driverClass}"></property> 9 10 <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>11 <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>12 </bean>13 14 15 16 <!-- 配置事物管理器:针对数据源 -->17 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">18 <property name="dataSource" ref="dataSource"></property>19 </bean>20 <!-- 启用事物注解:需要导入tx命名空间 -->21 <tx:annotation-driven transaction-manager="transactionManager"/>
2)在对应的方法前加入@Transactional 注解
1 @Transactional 2 public void purchase(String username, String isbn) { 3 4 //1.读取书的单价 5 int price = bookShopDao.findBookPirceByIsbn(isbn); 6 7 //2.更新书的库存 8 bookShopDao.updateBookStock(isbn); 9 10 //3.更新用户的余额11 bookShopDao.updateUserAccount(username, price);12 13 }
7.事物的其他属性
1)事务传播属性:当事务方法被另一个事务方法调用时, 必须指定事务应该如何传播. 例如: 方法可能继续在现有事务中运行, 也可能开启一个新事务, 并在自己的事务中运行. 事务的传播行为可以由传播属性指定. Spring 定义了 7 种类传播行为.
2)@Transactional(propagation=Propagation.REQUIRED) 使用propagation 指定事物传播行为,即当前的事物方法被另外一个事物调用时,如何使用事物。默认值为 REQUIRED
3)isolation 指定事物的隔离级别 ,最常见值为READ_COMMITTED
4)默认情况下 Spring 的声明式事物对所有的运行时异常进行回滚,也可以通过对应的属性设置.通常取默认值
① 事务的回滚规则可以通过 @Transactional 注解的 rollbackFor 和 noRollbackFor 属性来定义. 这两个属性被声明为 Class[] 类型的, 因此可以为这两个属性指定多个异常类
rollbackFor: 遇到时必须进行回滚
5)使用readOnly 指定事物为只读.表示这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务.若真的是一个只读取数据库值的方法,应设置readOnly=true
6)使用timeout 指定强制混滚之前事物可以占用的时间 ,单位 秒
① 由于事务可以在行和表上获得锁, 因此长事务会占用资源, 并对整体性能产生影响.
② 如果一个事物只读取数据但不做修改, 数据库引擎可以对这个事务进行优化.
③超时事务属性: 事务在强制回滚之前可以保持多久. 这样可以防止长期运行的事务占用资源.
1 @Transactional(propagation=Propagation.REQUIRED ,2 isolation=Isolation.READ_COMMITTED,3 noRollbackFor={UserAccountException.class},4 readOnly=false,5 timeout=1)6 public void purchase(String username, String isbn) {
}
[原创]java WEB学习笔记109:Spring学习---spring中事物管理