事务
- 事务一般特指数据库事务,是指作为一个程序执行单元执行的一系列操作,要么完全执行,要么完全不执行。
事务四大特性
1、原子性:一个事务(可能包含多条SQL)是一个不可分割的工作单位。
2、一致性:事务必须是使数据库从一个一致性状态变到另一个一致性状态。
3、隔离性:一个事务的执行不能被其他事务干扰。
4、持久性:一个事务一旦提交,它对数据库中数据的改变应该是永久性的。
Mysql事务处理
- 只有Innodb存储引擎支持事务。
-
Mysql默认以自动提交模式运行。
图片.png
图片.png
图片.png

事务隔离级别

- 查看隔离级别:select @@transaction_isolation
--设置事务隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 脏读
-- 事务A
begin;
select stock from products where id = '100001';
ROLLBACK;
-- 事务B
BEGIN;
UPDATE products set stock=0 where id = '100001';
ROLLBACK;
-- 不可重复读
-- 事务A
BEGIN;
select stock from products where id = '100001'; //第一步:第一次查询
select stock from products where id = '100001';//第三步:第二次查询
ROLLBACK;
-- 事务B
BEGIN;
UPDATE products SET STOCK = 0 WHERE ID = '100001'; //第二步:事务B提交
COMMIT;
--幻读
--事务A
BEGIN;
UPDATE products SET stock = 0; //第一步
select * from products; //第三步
ROLLBACK;
--事务B
BEGIN;
INSERT INTO products VALUES('100005','',1999,100,'正常'); //第二步
COMMIT;
JDBC事务处理
Connection接口
- JDBC的事务处理是基于Connection的,JDBC通过Connection对象进行事务管理。
- JDBC默认事务处理行为是自动提交。
事务相关方法
- setAutoCommit
设置自动提交 - commit
提交事务 - rollback
回滚事务
package com.alan.dao;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class OrderTest {
private String driver = "com.mysql.cj.jdbc.Driver";
private String url = "jdbc:mysql:///os?characterEncoding=utf8";
private String userName = "root";
private String password = "root";
@Test
public void addOrder(){
Connection connection = null;
try {
Class.forName(driver);
connection = DriverManager.getConnection(url,userName,password);
//封装为一个事务
connection.setAutoCommit(false);
Statement statement = connection.createStatement();
statement.execute("insert into orders values('100002','100001',2,2499,now(),null,null,'刘备','1330000000','成都','待发货')");
statement.execute("update products set stock= stock-2 where id='100001'");
statement.close();
//提交事务
connection.commit();
} catch (Exception e) {
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
connection = null;
}
}
}

Spring事务处理API


- 持久层提供基本的操作,业务层进行事务的封装处理
Spring事务处理-基于底层API

- OrderService
package com.alan.service;
import com.alan.entity.Order;
public interface OrderService {
void addOrder(Order order);
}
- OrderServiceImpl
package com.alan.service.impl2;
import com.alan.dao.OrderDao;
import com.alan.dao.ProductDao;
import com.alan.entity.Order;
import com.alan.entity.Product;
import com.alan.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import java.util.Date;
@Service
public class OrderServiceImpl implements OrderService {
//通过Spring自动注入
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
//事务管理器
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
@Override
public void addOrder(Order order) {
order.setCreateTime(new Date());
order.setStatus("待付款");
//开启事务
TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
try {
//以下两个操作用事务封装在一起
orderDao.insert(order);
Product product = productDao.select(order.getProductsId());
product.setStock(product.getStock() - order.getNumber());
productDao.update(product);
//提交事务
transactionManager.commit(transaction);
}catch (Exception e){
//碰到异常,回滚事务
e.printStackTrace();
transactionManager.rollback(transaction);
}
}
}
编程式处理方式二
<?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"
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">
<import resource = "applicationContext.xml"/>
<context:component-scan base-package="com.alan.service.impl2"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
</beans>
package com.alan.service.impl2;
import com.alan.dao.OrderDao;
import com.alan.dao.ProductDao;
import com.alan.entity.Order;
import com.alan.entity.Product;
import com.alan.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.Date;
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Autowired
private TransactionTemplate transactionTemplate;
public void addOrder(final Order order) {
order.setCreateTime(new Date());
order.setStatus("待付款");
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus transactionStatus) {
try {
orderDao.insert(order);
Product product = productDao.select(order.getProductsId());
product.setStock(product.getStock() - order.getNumber());
productDao.update(product);
}catch (Exception e){
e.printStackTrace();
transactionStatus.setRollbackOnly();
}
return null;
}
});
}
}
Spring事务处理-基于拦截器 TransactionInterceptor 方式
- Spring的声明式事务处理是建立在AOP的基础之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
- 开发中建议使用声明式事务,方便后期代码维护。
- 实现类
package com.alan.service.impl;
import com.alan.dao.OrderDao;
import com.alan.dao.ProductDao;
import com.alan.entity.Order;
import com.alan.entity.Product;
import com.alan.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import java.util.Date;
@Service
public class OrderServiceImpl implements OrderService {
//通过Spring自动注入
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Override
public void addOrder(Order order) {
//声明式,代码只是业务层的。
order.setCreateTime(new Date());
order.setStatus("待付款");
orderDao.insert(order);
Product product = productDao.select(order.getProductsId());
product.setStock(product.getStock() - order.getNumber());
productDao.update(product);
}
}
- 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:context="http://www.springframework.org/schema/context"
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">
<import resource = "applicationContext.xml"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--目标对象-->
<bean id="orderServiceTarget" class="com.alan.service.impl.OrderServiceImpl"></bean>
<!--配置拦截器-->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!--配置事务管理器-->
<property name="transactionManager" ref="transactionManager"></property>
<!--事务属性-->
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="search*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!--将上面二者关联起来-->
<bean id="orderService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--配置目标类-->
<property name="target" ref="orderServiceTarget"></property>
<!--配置拦截器名称-->
<property name="interceptorNames">
<list>
<idref bean="transactionInterceptor"></idref>
</list>
</property>
</bean>
</beans>
Spring事务处理-基于拦截器 TransactionProxyFactoryBean 方式(对上一种的简化方式)
<?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"
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">
<import resource = "applicationContext.xml"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--目标对象-->
<bean id="orderServiceTarget" class="com.alan.service.impl.OrderServiceImpl"></bean>
<!--组合配置-->
<bean id="orderService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"></property>
<!--目标类配置-->
<property name="target" ref="orderServiceTarget"></property>
<!--拦截器配置-->
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="search*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
Spring基于<tx>命名空间的声明式事务处理 (实际用的多)
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<import resource = "applicationContext.xml"/>
<!--开启自动扫描-->
<context:component-scan base-package="com.alan.service.impl"></context:component-scan>
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置通知,也就是拦截后要处理的方法-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--name中为实现类里面具体的方法-->
<tx:method name="get*" propagation="REQUIRED" read-only="true"/>
<tx:method name="find*" propagation="REQUIRED" read-only="true"/>
<tx:method name="search*" propagation="REQUIRED" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--aop相关配置-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.alan.service.impl.OrderServiceImpl.*.*(..))"></aop:pointcut>
<!--关联起来-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
网友评论