概述
Spring中的事物管理
注:本文用到的jar包请在同类文章Spring(1-1、基于xml装配Bean)中查找。
事务管理是企业级应用程序开发中必不可少的技术, 用来确保数据的完整性和一致性.
事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用
事务的四个关键属性(ACID)
原子性(atomicity): 事务是一个原子操作, 由一系列动作组成. 事务的原子性确保动作要么全部完成要么完全不起作用.
一致性(consistency): 一旦所有事务动作完成, 事务就被提交. 数据和资源就处于一种满足业务规则的一致性状态中.
隔离性(isolation): 可能有许多事务会同时处理相同的数据, 因此每个事物都应该与其他事务隔离开来, 防止数据损坏.
持久性(durability): 一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响. 通常情况下, 事务的结果被写到持久化存储器中事物的传播属性
REQUIRED_NEW传播属性
另一种常见的传播行为是REQUIRES_NEW. 它表示该方法必须启动一个新事务, 并在自己的事务内运行. 如果有事务在运行, 就应该先挂起它
方法上面的标注:@Transactional(propagation = Propagation.REQUIRES_NEW)
public void purchase(String username, String isbn) {
原理图
使用到的表结构
CREATE TABLE `account` (
`username` varchar(255) COLLATE utf8_bin NOT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `book` (
`isbn` int(255) NOT NULL AUTO_INCREMENT,
`book_name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`price` double(10,2) DEFAULT NULL,
PRIMARY KEY (`isbn`)
) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `book_stock` (
`isbn` int(11) NOT NULL,
`stock` int(11) DEFAULT NULL,
PRIMARY KEY (`isbn`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
Spring的声明式事物(注解)
dao
public interface BookShopDao {
/**根据书号获取数的单价*/
public int findBookPriceByIsbn(String isbn);
/** 更新库存,是书号对应的库存*/
public void updateBookStock(String isbn);
/**更新用户的账户余额,使username的balance-price */
public void updateUserAccount(String username, int price);
}
@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao {
@Autowired
private JdbcTemplate jt;
public int findBookPriceByIsbn(String isbn) {
String sql = "SELECT price FROM book WHERE isbn=?";
return jt.queryForObject(sql, Integer.class, isbn);
}
public void updateBookStock(String isbn) {
// 检查书的库存是否足够,若不够,则抛出异常
String sql2 = "SELECT stock FROM book_stock WHERE isbn=?";
Integer stock = jt.queryForObject(sql2, Integer.class, isbn);
if (stock == 0) {
throw new BookStockException("库存不足!");
}
String sql = "UPDATE book_stock SET stock=stock-1 WHERE isbn=?";
int update = jt.update(sql, isbn);
System.out.println("更新了-->" + update + "条");
}
public void updateUserAccount(String username, int price) {
// 验证用户的余额是否足够
String banalce = "SELECT balance FROM account WHERE username=?";
int ba = jt.queryForObject(banalce, Integer.class, username);
if (ba > 0 && ba < price) {
throw new UserAccountException("账户余额不足!");
}
String sql = "UPDATE account SET balance=balance-? WHERE username=?";
int update = jt.update(sql, price, username);
System.out.println("更新了-->" + update + "条");
}
}
service
public interface BookShopService {
public void purchase(String username, String isbn);
}
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService {
@Autowired
private BookShopDao bsd;
@Transactional
public void purchase(String username, String isbn) {
// 1获取书的单价
int price = bsd.findBookPriceByIsbn(isbn);
// 2更新数的库存
bsd.updateBookStock(isbn);
// 3更新用户的余额
bsd.updateUserAccount(username, price);
}
}
配置xml
<context:component-scan base-package="com.spring.beans"></context:component-scan>
<!-- 导入配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置数据源 -->
<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="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></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>
<!-- 配置事物管理器 -->
<bean id="tx"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 启用事物注解-->
<tx:annotation-driven transaction-manager="tx" />
测试类:[测试的时候试着去掉service方法上面的@Transactional和不去掉就可以看出事物起到的作用]
public class BookShopDaoImplTest {
private ApplicationContext ctx = null;
private BookShopService bookShopService = null;
{
ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
bookShopService = (BookShopService) ctx.getBean("bookShopService");
}
@Test
public void testbookShopService() {
bookShopService.purchase("AA", "1001");
}
}
总结:
1、在xml文件中添加两个配置
<bean id="tx"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="tx" />
2、在对应的service方法上添加@Transactional就可以
事物的其他属性(隔离级别,回滚,超时,只读)
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService {
@Autowired
private BookShopDao bsd;
// 1.使用propagation指定事物的传播行为
// 如何使用事物,默认取值为REQUIRED,即使用调用方法的事物
// 2.REQUIRES_NEW:事物自己的事物,调用的事物方法的事物挂起
// 使用isolation指定书屋的隔离级别,最常用的取值是read_commited
// 3.默认情况下Spring对声明式事物对所有的运行时异常进行回滚,也可以通过对应的属性进行设置。通常情况下取默认值即可
// 4.使用readOnly指定事物是否为只读,表示这个事物只读数据但不更新数据,这样可以帮助数据库引擎优化事物
// 若真的是一个只读数据库值的方法,应设置为readOnly=true
// 5.使用timeout指定强制回滚之前事物占用的时间
// @Transactional(propagation = Propagation.REQUIRED, isolation =
// Isolation.READ_COMMITTED, noRollbackFor = { UserAccountException.class })
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, readOnly = false, timeout = 3)
public void purchase(String username, String isbn) {
try {
Thread.sleep(5000);
} catch (Exception e) {
System.out.println(e.getMessage());
}
// 1获取书的单价
int price = bsd.findBookPriceByIsbn(isbn);
// 2更新数的库存
bsd.updateBookStock(isbn);
// 3更新用户的余额
bsd.updateUserAccount(username, price);
}
}
最后
以上就是不安故事为你收集整理的Spring(5、基于注解的事物)Spring中的事物管理的全部内容,希望文章能够帮你解决Spring(5、基于注解的事物)Spring中的事物管理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复