ACID
原子性
一致性
隔离性
持久性
脏读(dirty read) 一个事务读取了另一个事务尚未提交的数据,
不可重复读(non-repeatable read) 一个事务的操作导致另一个事务前后两次读取到不同的数据
幻读(phantom read) 一个事务的操作导致另一个事务前后两次查询的结果数据量不同。
1, 脏读
一个事务读到另一个事务,尚未提交的修改,就是脏读。
2,不可重复读。
在同一个事务中,再次读取数据时【就是你的select操作】,所读取的数据,和第1次读取的数据,不一样了。就是不可重复读。
3,幻读
事务1读取指定的where子句所返回的一些行。然后,事务2插入一个新行,这个新行也满足事务1使用的查询
where子句。然后事务1再次使用相同的查询读取行,但是现在它看到了事务2刚插入的行。这个行被称为幻象,
因为对事务1来说,这一行的出现是不可思议的。
JDBC定义了五种事务隔离级别:
TRANSACTION_NONE JDBC驱动不支持事务
TRANSACTION_READ_UNCOMMITTED 允许脏读、不可重复读和幻读。
TRANSACTION_READ_COMMITTED 禁止脏读,但允许不可重复读和幻读。
TRANSACTION_REPEATABLE_READ 禁止脏读和不可重复读,单运行幻读。
TRANSACTION_SERIALIZABLE 禁止脏读、不可重复读和幻读。
接口 PlatFormTransactionManager
package org.springframework.transaction.support;
类 TransactionTemplate
注意:用于异常捕获回滚
回滚的底层用的
rollback
接口 TransactionStatus
注意:用于单一接口mysql 执行状态判断回滚
如果mysql执行 结果为 0
自己抛一个异常 就全部都回滚了
restModel productMysqlTransactionTemplate.execute(new TransactionCallback()
@Autowired
private TransactionTemplat productMysqlTransactionTemplate;
restModel = productMysqlTransactionTemplate.execute(new TransactionCallback()
doInTransaction(TransactionStatus transactionStatus)
private PlatformTransactionManager transactionManager;
@Override
public T execute(TransactionCallback action) throws TransactionException {
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
else {
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
result = action.doInTransaction(status);
}
catch (RuntimeException ex) {
// Transactional code threw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Error err) {
// Transactional code threw error -> rollback
rollbackOnException(status, err);
throw err;
}
catch (Exception ex) {
// Transactional code threw unexpected exception -> rollback
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, “TransactionCallback threw undeclared checked exception”);
}
this.transactionManager.commit(status);
return result;
}
}
public interface CallbackPreferringPlatformTransactionManager extends PlatformTransactionManager {
<T> T execute(TransactionDefinition definition, TransactionCallback<T> callback)
throws TransactionException;
}
restModel = productMysqlTransactionTemplate.execute(new TransactionCallback() {
@Override
public RestModel doInTransaction(TransactionStatus transactionStatus) {
RestModel restModel1;
//验证行程编号
String tripCode = product.getTrip().getTrip_code();
if(StringUtils.isNotEmpty(tripCode)){
boolean flag = btProductDAO.ifExistTripCode(tripCode);
if(flag){
restModel1 = RestModel.data(ResultStatusEnum.TRAVELNUMBERHASALREADYEXISTED.getStatus(), “行程编号已经存在,不可重复同步。”);
return restModel1;
}
}
//操作产品基础信息表
BTProductMainInfo info = product.getMainInfo();
int homeid = btProductDAO.findHomeAbroad(info.getDestination_city_id());
info.setHome_abroad(homeid);
int vendorCompanyId = btProductDAO.findVendorCompanyId(info.getCreate_user_id());
info.setVendor_company_id(vendorCompanyId);
int flag = btProductDAO.insertProductMainInfo(info);
if (flag == 0) {
restModel1 = RestModel.data(ResultStatusEnum.OPERATIONPRODUCTFAILURE.getStatus(), “产品基础信息添加失败”);
return restModel1;
}
int productId = info.getId();
BTProductSupplementaryInfo supplementaryInfo = product.getSupplementaryInfo();
if (supplementaryInfo != null) {
//新增产品附表
supplementaryInfo.setProduct_id(productId);
btProductDAO.insertProductSupplementaryInfo(supplementaryInfo);
}
//操作线路行程
BTProductTrip trip = product.getTrip();
if (trip != null) {
trip.setProduct_id(productId);
//行程表
btProductDAO.insertProductTrip(trip);
int tripId = trip.getId();
List tripList = trip.getTripDaysList();
if (CollectionUtils.isNotEmpty(tripList)) {
for (BTProductTripDays day : tripList) {
day.setProduct_id(productId);
day.setTrip_id(tripId);
//天表
btProductDAO.insertProductTripDays(day);
int dayId = day.getDay_id();
List chipsList = day.getTripChipsList();
if (CollectionUtils.isNotEmpty(chipsList)) {
for (BTProductTripChips chip : chipsList) {
chip.setDay_id(dayId);
}
//行程段
btProductDAO.insertProductTripChips(chipsList);
}
List<BTProductTripShops> shopsList = day.getTripShopsList();
if (CollectionUtils.isNotEmpty(shopsList)) {
for (BTProductTripShops shop : shopsList) {
shop.setDay_id(dayId);
}
//行程商店
btProductDAO.insertProductTripShops(shopsList);
}
}
}
}
restModel1 = RestModel.data(productId);
return restModel1;
}
});
} catch (Exception e) {
restModel = RestModel.data(ResultStatusEnum.ERROR.getStatus(), e.getMessage());
}finally {
HashMap logMap = new HashMap();
logMap.put("methodName", "insertProductMainInfo");
logMap.put("requestId", requestId);
logMap.put("timeStamp", timeStamp);
logMap.put("authentication", authentication);
logMap.put("productInfo", product);
logMap.put("response", restModel);
logger.info(JSON.toJSONString(logMap));
}
return restModel;
}
2阶段
准备阶段 提交阶段
准备阶段:写redo或者undo日志 锁定资源,执行操作,但并不提交。
提交阶段:告诉准备成功,开始提交,锁定的资源,如何有任何人失败,终止任务,执行undo日志回滚,释放锁定的资源。
3 阶段多了一个询问阶段,减少锁定超时问题
CAP
1.C:Consistency,一致性, 数据一致更新,所有数据变动都是同步的
2.A:Availability,可用性, 好的响应性能,完全的可用性指的是在任何故障模型下,服务都会在有限的时间处理响应
3.P:Partition tolerance,分区容错性,可靠性
任何系统只能满足2点,采用补偿策略达到最终一致性。
BASE
模型包含个三个元素:
1.BA:Basically Available,基本可用
2.S:Soft State,软状态,状态可以有一段时间不同步
3.E:Eventually Consistent,最终一致,最终数据是一致的就可以了,而不是时时保持强一致
TCC
t 执行 c 确认 c 回滚
mysql 5.7 分布式事务 xa 2阶段提交
还是需要业务代码控制
分布式事务通常采用2PC协议,全称Two Phase Commitment Protocol。该协议主要为了解决在分布式数据库场景下,所有节点间数据一致性的问题。在分布式事务环境下,事务的提交会变得相对比较复杂,因为多个节点的存在,可能存在部分节点提交失败的情况,即事务的ACID特性需要在各个数据库实例中保证。总而言之,在分布式提交时,只要发生一个节点提交失败,则所有的节点都不能提交,只有当所有节点都能提交时,整个分布式事务才允许被提交。分布式事务通过2PC协议将提交分成两个阶段,在第一阶段,所有参与全局事务的节点都开始准备(PREPARE),告诉事务管理器它们准备好提交了。在第二阶段,事务管理器告诉资源管理器执行ROLLBACK还是COMMIT。如果任何一个节点显示不能提交,则所有的节点都被告知需要回滚。可见与本地事务不同的是,分布式事务需要多一次的PREPARE操作,待收到所有节点的同意信息后,再进行COMMIT或是ROLLBACK操作。