一、Spring事务
- Spring事务是基于AOP环绕通知和异常通知实现的
- Spring事务:编程式事务、声明式事务
- Spring事务底层:使用编程式事务+AOP技术进行包装的=声明式事务
二、AOP简介
- AOP概念:Aspect Oriented Programming面向切面编程,解决代码复用问题
- AOP底层实现原理:代理设计模式
- 为什么要使用AOP技术:代码复用、解耦
- AOP的主要应用:日志记录,性能统计,安全控制,事务处理,异常处理
三、静态代理
public interface UserService {
public void add();
}
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("往数据库添加数据...");
}
}
public class UserServiceProxy {
private UserService userService;
public UserServiceProxy(UserService userService) {
this.userService = userService;
}
public void add() {
System.out.println("静态代理 开启事务");
userService.add();
System.out.println("静态代理 提交事务");
}
}
public class App{
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy(userService);
userServiceProxy.add();
}
}
四、动态代理设计模式
public interface UserService {
public void add();
}
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("往数据库添加数据...");
}
}
public class InvocationHandlerImpl implements InvocationHandler {
private Object target;
public InvocationHandlerImpl(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("使用jdk动态代理 开启事务");
result = method.invoke(target, args);
System.out.println("使用jdk动态代理 提交事务");
return result;
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
UserService userService = new UserServiceImpl();
InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userService);
ClassLoader loader = userService.getClass().getClassLoader();
Class<?>[] interfaces = userService.getClass().getInterfaces();
UserService newProxyInstance = (UserService) Proxy.newProxyInstance(loader, interfaces,
invocationHandlerImpl);
newProxyInstance.add();
}
}
五、AOP注解事务实现
1、POM
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_2</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
</dependencies>
2、spring.xml
- 路径位置:src/main/resources/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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.sjyl"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3、注解方式实现AOP
public interface UserService {
public void add();
}
@Service
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("往数据库添加数据...");
}
}
@Component
@Aspect
public class AopLog {
@Before("execution(* com.sjyl.aop.UserService.add(..))")
public void before() {
System.out.println("前置通知 在方法之前执行...");
}
@After("execution(* com.sjyl.aop.UserService.add(..))")
public void after() {
System.out.println("前置通知 在方法之后执行...");
}
@AfterReturning("execution(* com.sjyl.aop.UserService.add(..))")
public void returning() {
System.out.println("运行通知");
}
@AfterThrowing("execution(* com.sjyl.aop.UserService.add(..))")
public void afterThrowing() {
System.out.println("异常通知");
}
@Around("execution(* com.sjyl.aop.UserService.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
{
System.out.println("环绕通知 调用方法之前执行");
proceedingJoinPoint.proceed();
System.out.println("环绕通知 调用方法之后执行");
}
}
public class Test001 {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
userService.add();
}
}
六、Spring事务特性
1、原子性(Atomicity)
- 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响
2、一致性(Consistency)
- 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
- 拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性
3、隔离性(Isolation)
- 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
- 即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行
4、持久性(Durability)
- 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
- 例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误
七、手写Spring编程事务
1、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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.sjyl"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
2、TransactionUtils
@Component
public class TransactionUtils {
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
public TransactionStatus begin() {
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
return transaction;
}
public void commit(TransactionStatus transaction) {
dataSourceTransactionManager.commit(transaction);
}
public void rollback(TransactionStatus transaction) {
dataSourceTransactionManager.rollback(transaction);
}
}
3、手写编程事务
public interface UserService {
public void add();
}
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void add(String name, Integer age) {
String sql = "INSERT INTO t_users(NAME, age) VALUES(?,?);";
int updateResult = jdbcTemplate.update(sql, name, age);
System.out.println("updateResult:" + updateResult);
}
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Autowired
private TransactionUtils transactionUtils;
public void add() {
TransactionStatus transactionStatus = null;
try {
transactionStatus = transactionUtils.begin();
userDao.add("test001", 20);
System.out.println("开始报错啦!@!!");
System.out.println("################");
userDao.add("test002", 21);
if (transactionStatus != null)
transactionUtils.commit(transactionStatus);
} catch (Exception e) {
e.getMessage();
if (transactionStatus != null)
transactionUtils.rollback(transactionStatus);
}
}
}
八、AOP整合编程事务
1、AopTransaction
@Component
@Aspect
public class AopTransaction {
@Autowired
private TransactionUtils transactionUtils;
@AfterThrowing("execution(* com.sjyl.service.UserService.add(..))")
public void afterThrowing() {
System.out.println("回滚事务");
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
@Around("execution(* com.sjyl.service.UserService.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("开启事务");
TransactionStatus transactionStatus = transactionUtils.begin();
proceedingJoinPoint.proceed();
System.out.println("提交事务");
transactionUtils.commit(transactionStatus);
}
}
2、UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Autowired
private TransactionUtils transactionUtils;
public void add() {
try {
userDao.add("test001", 20);
int i = 1 / 0;
System.out.println("################");
userDao.add("test002", 21);
} catch (Exception e) {
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
}