1 事务概述
●在JavaEE企业级开发的应用领域,为了保证数据的完整性和一致性,必须引入数据库事务的概念,所以事务管理是企业级应用程序开发中必不可少的技术。
●事务就是一组由于逻辑上紧密关联而合并成一个整体(工作单元)的多个数据库操作,这些操作要么都执行,要么都不执行。
●事务的四个关键属性(ACID)
○原子性(atomicity):“原子”的本意是“不可再分”,事务的原子性表现为一个事务中涉及到的多个操作在逻辑上缺一不可。事务的原子性要求事务中的所有操作要么都执行,要么都不执行。
○一致性(consistency):“一致”指的是数据的一致,具体是指:所有数据都处于满足业务规则的一致性状态。一致性原则要求:一个事务中不管涉及到多少个操作,都必须保证事务执行之前数据是正确的,事务执行之后数据仍然是正确的。如果一个事务在执行的过程中,其中某一个或某几个操作失败了,则必须将其他所有操作撤销,将数据恢复到事务执行之前的状态,这就是回滚。
○隔离性(isolation):在应用程序实际运行过程中,事务往往是并发执行的,所以很有可能有许多事务同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。隔离性原则要求多个事务在并发执行过程中不会互相干扰。
○持久性(durability):持久性原则要求事务执行完成后,对数据的修改永久的保存下来,不会因各种系统错误或其他意外情况而受到影响。通常情况下,事务对数据的修改应该被写入到持久化存储器中。
声明式事务:
以前通过复杂的编程来编写一个事务,替换为只需要告诉Spring哪个方法是事务方法即可;
Spring自动进行事务控制;
编程式事务:
TransactionFilter{
try{
//获取连接
//设置非自动 提交
chain.doFilter();
//提交
}catch(Exception e){
//回滚
}finllay{
//关闭连接释放资源
}
}
AOP:环绕通知可以去做;
//获取连接
//设置非自动 提交
目标代码执行
//正常提交
//异常回滚
//最终关闭
最终效果:
BookService{
@this is a tx-method(Transactional)
public void checkout(){
//xxxxx
}
}
事务管理代码的固定模式作为一种横切关注点,可以通过AOP方法模块化,进而借助Spring AOP框架实现声明式事务管理。
自己要写这个切面还是很麻烦;
这个切面已经有了;(事务切面===事务管理器);
这个事务管理器就可以在目标方法运行前后进行事务控制(事务切面);
我们目前都使用DataSourceTransactionManager;即可;
快速的为某个方法添加事务:
1)配置出这个事务管理器让他工作;
2)开启基于注解的事务
3)给事务方法加@Transactional注解
相关实例
BookDao.java:
package com.atguigu.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; /** * @Title: BookDao * @Description: * @Author: * @Version: 1.0 * @create 2020/6/9 10:05 */ @Repository public class BookDao { @Autowired JdbcTemplate jdbcTemplate; /** * 1、减余额 * * 减去某个用户的余额 */ public void updateBalance(String userName,int price){ String sql = "UPDATE account SET balance=balance-? WHERE username=?"; jdbcTemplate.update(sql, price,userName); } /** * 2、按照图书的ISBN获取某本图书的价格 * @return */ public int getPrice(String isbn){ //制造一个异常 String sql = "SELECTA price FROM book WHERE isbn=?"; return jdbcTemplate.queryForObject(sql, Integer.class, isbn); } /** * 3、减库存;减去某本书的库存;为了简单期间每次减一 */ public void updateStock(String isbn){ String sql = "UPDATE book_stock SET stock=stock-1 WHERE isbn=?"; jdbcTemplate.update(sql, isbn); } }
BookService.java:
package com.atguigu.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.atguigu.dao.BookDao; @Service public class BookService { @Autowired BookDao bookDao; /** * 结账;传入哪个用户买了哪本书 * @param username * @param isbn */ @Transactional public void checkout(String username,String isbn){ //1、减库存 bookDao.updateStock(isbn); int price = bookDao.getPrice(isbn); //2、减余额 bookDao.updateBalance(username, price); } }
ApplicationContext.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xmlns:tx="http://www.springframework.org/schema/tx" 6 xmlns:context="http://www.springframework.org/schema/context" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans.xsd 9 http://www.springframework.org/schema/tx 10 http://www.springframework.org/schema/tx/spring-tx.xsd 11 http://www.springframework.org/schema/aop 12 http://www.springframework.org/schema/aop/spring-aop.xsd 13 http://www.springframework.org/schema/context 14 http://www.springframework.org/schema/context/spring-context.xsd"> 15 16 17 <!--配置包扫描--> 18 <context:component-scan base-package="com.atguigu"></context:component-scan> 19 20 <!--引入外部配置文件--> 21 <context:property-placeholder location="classpath:db.properties"/> 22 23 <!--实验1:测试数据源 24 ${}取出配置文件中的值 25 #{}Spring的表达式语言 26 --> 27 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 28 <property name="user" value="${jdbc.username}"/> 29 <property name="password" value="${jdbc.password}"/> 30 <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/> 31 <property name="driverClass" value="${jdbc.dirverClass}"/> 32 </bean> 33 34 <!-- Spring提供了一个类JdbcTemplate,我们用它操作数据库; 35 导入Spring的数据库模块 36 spring-jdbc-4.0.0.RELEASE.jar 37 spring-orm-4.0.0.RELEASE.jar 38 spring-tx-4.0.0.RELEASE.jar 39 --> 40 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 41 <!--构造器注入--> 42 <!--<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>--> 43 <!--属性注入--> 44 <property name="dataSource" ref="dataSource"/> 45 </bean> 46 47 <!--事务控制--> 48 <!--1.配置事务管理器让其进行事务控制,一定导入面向编程的相关依赖--> 49 <bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 50 <!--控制住数据源--> 51 <property name="dataSource" ref="dataSource"/> 52 </bean> 53 54 <!--2.开启基于注解的事务控制,依赖tx名称空间--> 55 <!--如果之前定义的id为transactionManager,那么transaction-manager可以省略不写--> 56 <tx:annotation-driven transaction-manager="tm"/> 57 <!--3.给事务方法加注解@Transactional--> 58 59 </beans>
db.properties:
jdbc.username=root
jdbc.password=root
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/tx?serverTimezone=GMT%2B8
jdbc.dirverClass=com.mysql.cj.jdbc.Driver
TxTest.java:
package com.atguigu.test;
import com.atguigu.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Title: TxTest
* @Description:
* @Author:
* @Version: 1.0
* @create 2020/6/9 10:15
*/
public class TxTest {
ApplicationContext ioc = new ClassPathXmlApplicationContext("ApplicationContext.xml");
@Test
public void test01() {
BookService bookService = ioc.getBean(BookService.class);
bookService.checkout("Tom", "ISBN-001");
System.out.println("结账完成");
}
}