1.什么是事务
二.事务的传播性,简单的引用
创建maven项目,在pom.xml中加载架包
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn</groupId>
<artifactId>spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- 加载spring的包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.3</version>
</dependency>
<!-- 添加jdbc的架包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<!-- 加载数据库的架包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<!-- 面向切面编程 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
创建连接数据的四要素jdbc.properties文件
url=jdbc:mysql://localhost:3306/news
driverClassName=com.mysql.jdbc.Driver
userName1=root
password=123456
创建spring.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: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-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
">
<!-- 扫描bean -->
<context:component-scan base-package="less04.testm"></context:component-scan>
<context:property-placeholder location="classpath:/less04/jdbc.properties"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${url}" ></property>
<property name="username" value="${userName1}" ></property>
<property name="password" value="${password}" ></property>
<property name="driverClassName" value="${driverClassName}" ></property>
</bean>
<!-- 事务管理器 不再使用jdbc的commit和rollback 必须由事务管理器提供 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 定义通知 通知的代码 spring已经实现 -->
<tx:advice id="myAdvise" transaction-manager="transactionManager">
<tx:attributes>
<!--
propagation="REQUIRED" 方法和方法之间父子关系
REQUIRED 没有事务创建一个事务 有事务使用当前事务
REQUIRED_NEW 不管父方法是否存在事务 都会新建事务
SUPPORTS 父方法存在事务 使用当前事务 没有事务 使用jdbc的事务(自动提交)
NOT_SUPPORTED 不管父方法是否存在事务 都不会使用事务(挂起事务)
MANDATORY 必须在事务环境下运行 父方法没有事务 抛出异常
No existing transaction found for transaction marked with propagation 'mandatory'
NEVER 父方法不能存在 事务 有事务抛出异常
Existing transaction found for transaction marked with propagation 'never'
isolation="DEFAULT"隔离级别
DEFAULT使用数据库本身的隔离级别ORACLE(读已提交)MYSQL(可重复读)
READ_UNCOMMITTED spring实现读未提交(脏读)
REA_COMMITTED spring实现读已提交(不重复读+幻读)
REPEATABLE_READ spring实现可重复读(幻读)
SERIALIZABLE spring实现串行化(已解决)
spring事务运行过程中碰到运行时异常自动回滚 非运行时异常不会回滚
rollback-for=""指定会自动回滚的非运行时异常
no-rollback-for=""指定某些运行时异常抛出时不回滚
只读事务(除特定的方法以外其他的业务逻辑方法都不应该操作事务)
read-only="true"设置只读事务
timeout=""设置超时时间
-->
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="save*" />
<tx:method name="delete*"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 定义切点 advice-ref引用通知 -->
<aop:config>
<aop:pointcut expression="execution(* less04.testm.dao.*.*(..)) " id="myPoint"/>
<aop:advisor advice-ref="myAdvise" pointcut-ref="myPoint"/>
</aop:config>
</beans>
持久层
package less04.testm.dao;
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class AcDaoImpl {
@Autowired
JdbcTemplate jdbc;
@Autowired
BcDaoImpl b;
public void updateAminus(int money) throws SQLException{
//扣钱
String sql="update mymoney set lostedmoney=lostedmoney-"+money+" where usid=1";
jdbc.execute(sql);
//加钱
b.saveBadd(money);
int i=5/0;
}
}
package less04.testm.dao;
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BcDaoImpl {
@Autowired
JdbcTemplate jdbc;
public void saveBadd(int money) throws SQLException{
String sql="update mymoney set lostedmoney=lostedmoney+"+money+" where usid=2";
jdbc.execute(sql);
}
}
测试main方法
import java.sql.SQLException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import less04.testm.dao.AcDaoImpl;
/**
* 编程式事务
* 声明式事务
* xml声明(全局)
* 注解声明
*/
public class TestTa {
static AcDaoImpl myMoneyDao;
static{
ApplicationContext context = new GenericXmlApplicationContext("classpath:less04/testm/spring.xml");
myMoneyDao=(AcDaoImpl)context.getBean("acDaoImpl");
}
public static void main(String[] args) throws SQLException {
myMoneyDao.updateAminus(10);
}
}
三.事务的隔离级别
1.什么是事务的隔离级别
事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:
脏读:一个事务读到另一个事务未提交的更新数据。
幻读:例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样。
不可重复读:比方说在同一个事务中先后执行两条一模一样的select语句,期间在此次事务中没有执行过任何DDL语句,但先后得到的结果不一致,这就是不可重复读。
2.Spring支持的隔离级别1.DEFAULT 使用数据库本身的隔离级别ORACLE(读已提交)MYSQL(可重复读)
2. READ_UNCOMMITTED 读未提交(脏读)最低的隔离级别,一切皆有可能。 spring实现读未提交(脏读)
3.REA_COMMITTED 读已提交,ORACLE默认隔离级别,有幻读以及不可重复读风险 .spring 实现读已提交(不重复读+幻读)
4.REPEATABLE_READ 可重复读,解决不可重复读的隔离级别,但还是有幻读风险.spring实现可重复读(幻读)
5.SERIALIZABLE 串行化,最高隔离级别,杜绝一切隐患,缺点是效率低.spring实现串行化(已解决)
3.事务的回滚
spring事务运行过程中碰到运行时异常自动回滚 非运行时异常不会回滚
rollback-for=""指定会自动回滚的非运行时异常
no-rollback-for=""指定某些运行时异常抛出时不回滚
timeout=""设置超时时间 超时时间一般在5到20之间