1.什么是事务
事务(TRANSACTION) 是作为单个逻辑工作单元执行的一系列操作。
多个操作作为一个整体向系统提交,要么都执行,要么都不执行
事务是一个无可再分的逻辑单元
2.事务的特性
四个属性,简称ACDI属性
原子性(Atomicity)
事务是一个完整的操作,事务的各个操作都是不可再分的,要么都执行,要么都不执行
一致性(Consistency)
当事务完成后,数据必须处于一致性
隔离性(Isolation)
并发事务之间相互隔离,独立,他不应以任何形式依赖于或影响其他事务
持久性(Durability)
事务完成后,他对数据的修改是永久性的;
3.隔离问题
脏读
一个事务读到另一个事务没有提交的数据
不可重复读
一个事务读到另一个事务已经提交的数据(正常现象,主要发生在update)
幻读(虚读)
一个事务读到另一个事务已经提交的数据(正常现象,主要发生在insert)
4.隔离级别
read uncommitted:
读未提交。存在3个问题(脏读,可重复读,虚读)
read committed:
读已提交。解决脏读,存在2个问题(可重复读,虚读)
repeatable read:
可重复读。解决:脏读、不可重复读,存在1个问题。(虚读)
serializable :
串行化。都解决,单事务。
注意:这里是以级别从低到高排列的,不过他们的效率却是以高到低的,(一般使用第二、三个)
5.保存点
适用于多个事务都需要提交,不过有必须提交的事务,有的事务可提交
需求:AB(必须),CD(可选)
Connection conn = null;
Savepoint savepoint = null; //保存点,记录操作的当前位置,之后可以回滚到指定的位置。(可以回滚一部分)
try{
//1 获得连接
conn = ...;
//2 开启事务
conn.setAutoCommit(false);
A
B
//设置一个保存点
savepoint = conn.setSavepoint();
C
D
//3 提交事务
conn.commit();
} catche(){
if(savepoint != null){ //CD异常
// 回滚到CD之前
conn.rollback(savepoint);
// 提交AB
conn.commit();
} else{ //AB异常
// 回滚AB
conn.rollback();
}
}
6.转账案例:(使用事务的代理工厂)
需求:
A账户给B账户转账,A账户减多少钱,B账户就需要增加多少钱
若出现异常,事务回滚到事务发生之前的状态
数据库表:

导入依赖:(这里的Spring-jdbc以来中包含jdbcTemplate)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
创建entity
public class Student {
private Integer stuid;
private String stuname;
private Integer age;
public Integer getStuid() {
return stuid;
}
public void setStuid(Integer stuid) {
this.stuid = stuid;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
创建Dao
public interface IStudentdao {
//加年龄
public int jiaage(Integer sum);
//减年龄
public int jianage(Integer sum);
}
创建Daoimpl(这里我使用的是注释实现jdbcTemplate)
@Repository
public class IStudentdaoimpl implements IStudentdao {
@Resource
private JdbcTemplate jdbcTemplate;
@Override
public int jiaage(Integer sum) {
String sql="update student set age=age+? where stuid=1";
int update = this.jdbcTemplate.update(sql, sum);
return update;
}
@Override
public int jianage(Integer sum) {
String sql="update student set age=age-? where stuid=2";
int update = this.jdbcTemplate.update(sql, sum);
return update;
}
}
创建Service(因为加钱减钱是一步操作,所以在这里整合为一个方法)
public interface IStudentservice {
//转账
public int zhuanzhang();
}
创建Serviceimpl
@Service("iStudentservice")
public class IStudentserviceimpl implements IStudentservice {
@Resource
private IStudentdao iStudentdao;
public IStudentdao getiStudentdao() {
return iStudentdao;
}
public void setiStudentdao(IStudentdao iStudentdao) {
this.iStudentdao = iStudentdao;
}
Propagation.REQUIRES_NEW)
@Override
public int zhuanzhang() {
int jiaage = iStudentdao.jiaage(10);
//模拟一个异常
//int asd=5/0;
int jianage = iStudentdao.jianage(10);
return jianage+jiaage;
}
}
数据源文件
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/student?useUniCode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull jdbc.username=root jdbc.password=123
大配置文件
<?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"
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">
<!--扫描注解-->
<context:component-scan base-package="com.JdbcTemplate"/>
<!--记载配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--DateSource模板
DriverManagerDataSource:Spring默认的数据源
数据源还有:c3p0 dbcp
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--植入JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置Spring的事务管理器,默认在发生异常的情况下回滚,否则提交-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--植入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--Spring事务的代理工厂-->
<bean id="transactionFactory" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--指定事务管理器-->
<property name="transactionManager" ref="transactionManager"></property>
<!--目标对象-->
<property name="target" ref="iStudentservice"></property>
<!--设置方法-->
<property name="transactionAttributes">
<props> <!--指定隔离级别和传播行为-->
<prop key="zhuanzhang">ISOLATION_READ_COMMITTED,PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
</bean>
</beans>
测试
//工厂
@Test
public void shi(){
IStudentservice stu = (IStudentservice)atc.getBean("transactionFactory");
int zhuanzhang = stu.zhuanzhang();
System.out.println("转账成功!");
}


修改Serviceimpl(模拟一个异常)
@Service("iStudentservice")
public class IStudentserviceimpl implements IStudentservice {
@Resource
private IStudentdao iStudentdao;
public IStudentdao getiStudentdao() {
return iStudentdao;
}
public void setiStudentdao(IStudentdao iStudentdao) {
this.iStudentdao = iStudentdao;
}
@Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRES_NEW)
@Override
public int zhuanzhang() {
int jiaage = iStudentdao.jiaage(10);
//模拟一个异常
int asd=5/0;
int jianage = iStudentdao.jianage(10);
return jianage+jiaage;
}
}
继续测试

7.使用Aop事务
修改大配置文件
<?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"
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">
<!--扫描注解-->
<context:component-scan base-package="com.JdbcTemplate"/>
<!--记载配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--DateSource模板
DriverManagerDataSource:Spring默认的数据源
数据源还有:c3p0 dbcp
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--植入JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置Spring的事务管理器,默认在发生异常的情况下回滚,否则提交-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--植入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--AOP管理事务--><tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <!--实现事务的方法--> <tx:attributes> <tx:method name="zhuan*" isolation="READ_COMMITTED" propagation="REQUIRES_NEW"/> </tx:attributes></tx:advice><aop:config> <aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/> <aop:advisor advice-ref="transactionAdvice" pointcut-ref="pointcut"/></aop:config>
</beans>
测试
//aop
@Test
public void aopshi(){
IStudentservice stu = (IStudentservice)atc.getBean("iStudentservice");
int zhuanzhang = stu.zhuanzhang();
System.out.println("转账成功!");
}


模拟一个异常后


8.使用注释实现事务
修改大配置文件
<?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"
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">
<!--扫描注解-->
<context:component-scan base-package="com.JdbcTemplate"/>
<!--记载配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--DateSource模板
DriverManagerDataSource:Spring默认的数据源
数据源还有:c3p0 dbcp
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--植入JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置Spring的事务管理器,默认在发生异常的情况下回滚,否则提交-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--植入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--注解-->
<tx:annotation-driven/>
</beans>
修改Serviceimpl文件
@Service("iStudentservice")
public class IStudentserviceimpl implements IStudentservice {
@Resource
private IStudentdao iStudentdao;
public IStudentdao getiStudentdao() {
return iStudentdao;
}
public void setiStudentdao(IStudentdao iStudentdao) {
this.iStudentdao = iStudentdao;
}
@Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRES_NEW)
@Override
public int zhuanzhang() {
int jiaage = iStudentdao.jiaage(10);
//模拟一个异常
int asd=5/0;
int jianage = iStudentdao.jianage(10);
return jianage+jiaage;
}
}
测试
//注解
@Test
public void zhujie(){
IStudentservice stu = (IStudentservice)atc.getBean("iStudentservice");
int zhuanzhang = stu.zhuanzhang();
System.out.println("转账成功!");
}

