以 begin / start transaction 开始,commit / rollback 结束的事务。或者是带有保存点 savepoint 的事务。
2. 链式事务
一个事务在提交的时候自动将上下文传给下一个事务,也就是说一个事务的提交和下一个事务的开始是原子性的,下一个事务可以看到上一个事务的处理结果。MySQL 的链式事务靠参数 completion_type 控制,并且回滚和提交的语句后面加上 work 关键词。
3. 嵌套事务
有多个 begin / commit / rollback 这样的事务块的事务,并且有父子关系。子事务的提交完成后不会真的提交,而是等到父事务提交才真正的提交。
4. 自治事务
内部事务的提交不随外部事务的影响,一般用作记录内部事务的异常情况。MySQL 不支持自治事务,但是某些场景可以用 MySQL 的插件式引擎来变相实现。
这里以 MySQL 为例,其 MyISAM 引擎是不支持事务 *** 作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。
根据 MySQL 的官方文档:
https://dev.mysql.com/doc/refman/5.5/en/storage-engine-setting.html
从 MySQL 5.5.5 开始的默认存储引擎是:InnoDB,之前默认的都是:MyISAM,所以这点要值得注意,底层引擎不支持事务再怎么搞都是无济于事。
如下代码所示,当前数据源若没有配置事务管理器,那也是白搭!
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource)
}
如果此时把 @Service 注解注释掉,这个类就不会被加载成一个 Bean,那这个类就不会被 Spring 管理了,事务自然就失效了。
以下引自spring官方文档:
大致意思是:
@Transactional 只能用于 public 的方法上,否则事务会失效。如果要用在非 public 方法上,可以开启 AspectJ 代理模式。
例1:
例1 中,update方法上面没有加 @Transactional 注解,调用有 @Transactional 注解的 updateOrder 方法,updateOrder 方法上的事务管用吗?
例2:
例2 中,update方法上面加了 @Transactional 注解,调用有 @Transactional 注解的 updateOrder 方法,updateOrder 方法上的事务管用吗?
很遗憾,这两个例子中, updateOrder 方法上的事务都不管用
因为它们发生了自身调用,就是调该类自己的方法,而没有经过 Spring 的代理类,默认只有在外部调用事务才会生效,这也是老生常谈的经典问题了。
6.1这个也是出现比较多的场景:把异常吃了,然后又不抛出来,事务也不会回滚!
6.2
这样事务也是不生效的,因为默认回滚的是:RuntimeException,如果你想触发其他异常的回滚,需要在注解上配置一下,如:
@Transactional(rollbackFor = Exception.class)
这个配置仅限于 Throwable 异常类及其子类。
Propagation.NOT_SUPPORTED:表示不以事务运行,当前若存在事务则挂起。这表示不支持以事务的方式运行,所以即使事务生效也是白搭!
近来稍有时间研究了下MYSQL中的事务 *** 作,在很多场合下很是适用,譬如在注册的时候需要初始化很多张关联表的时候,问答回复的时候需要至少同时 *** 作两张表,这些都会在某些时候只能成功更新一张表,而另外的SQL语句出现错误,正常的 *** 作会导致初始化了一张表,其他的都木有能初始化,这个时候就会导致用户表里的用户信息已经执行插入,导致提示注册失败,但是用户已经注册了部分信息,这个时候需要程序员去数据库删除相应的数据是一个比较不好的事情。
因此这边考虑使用事务,事务可以进行模拟SQL *** 作,当所有的SQL都 *** 作成功的时候才进行SQL *** 作,只要有一个 *** 作失败就回滚当前事务的所有SQL *** 作,避免出现上面描述中出现的数据写入不完整等情况。
下面是鄙人写的一小段代码,欢迎大家参考和提出意见:
复制代码
代码如下:
/**
*
@todo
多条sql的事务处理
*
@param
$sqls
array
*
@return
boole
true/false
*/
public
function
doArraySqlActionsTran($password,$sqls){
$db
=
$this
->
doSqlLink($password)//打开数据库链接
$db
->
autocommit(FALSE)//设置为不自动提交,因为MYSQL默认立即执行
//获取SQL执行结果数组
for
($i=0$i<count($sqls)$i++){
$result[$i]
=
$db
->
query($sqls[$i])
}
//解析SQL执行结果数组
for
($j=0$j<count($result)$j++){
if
($result[$j]==FALSE){
$result[$j]='false'
}else{
$result[$j]='true'
}
}
//查找SQL结果数组中是否存在false结果集
if
(in_array('false',$result)){
$sqlResult=FALSE
}else{
$sqlResult==TRUE
}
//根据结果集进行数据库回滚或者执行 *** 作
if
($sqlResult==FALSE){
$db
->
rollback()//判断当执行失败时回滚
$return=FALSE//
正式环境中使用
//$return='ROOLBACK'//test
标记使用
}else{
$db
->
commit()//执行事务s
$return=TRUE//
正式环境中使用
//$return='COMMIT'//test
标记使用
}
$db->autocommit(true)
//设置为非自动提交——事务处理
$db->close()//关闭连接
return
$return
}
到此事务执行批量SQL *** 作基本完成,谢谢大家!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)