- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章mysql存储过程事务管理简析由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
ACID:Atomic、Consistent、Isolated、Durable 存储程序提供了一个绝佳的机制来定义、封装和管理事务。 1,MySQL的事务支持 1)MySQL的事务支持不是绑定在MySQL服务器本身,而是与存储引擎相关: Sql代码 。
复制代码代码如下
MyISAM:不支持事务,用于只读程序提高性能 InnoDB:支持ACID事务、行级锁、并发 Berkeley DB:支持事务 MyISAM:不支持事务,用于只读程序提高性能 InnoDB:支持ACID事务、行级锁、并发 Berkeley DB:支持事务 2) 隔离级别: 。
隔离级别决定了一个session中的事务可能对另一个session的影响、并发session对数据库的操作、一个session中所见数据的一致性 ANSI标准定义了4个隔离级别,MySQL的InnoDB都支持: Java代码 。
复制代码代码如下
READ UNCOMMITTED:最低级别的隔离,通常又称为dirty read,它允许一个事务读取还没commit的数据,这样可能会提高性能,但是dirty read可能不是我们想要的 READ COMMITTED:在一个事务中只允许已经commit的记录可见,如果session中select还在查询中,另一session此时insert一条记录,则新添加的数据不可见 REPEATABLE READ:在一个事务开始后,其他session对数据库的修改在本事务中不可见,直到本事务commit或rollback。在一个事务中重复select的结果一样,除非本事务中update数据库。 SERIALIZABLE:最高级别的隔离,只允许事务串行执行。为了达到此目的,数据库会锁住每行已经读取的记录,其他session不能修改数据直到前一事务结束,事务commit或取消时才释放锁。 READ UNCOMMITTED:最低级别的隔离,通常又称为dirty read,它允许一个事务读取还没commit的数据,这样可能会提高性能,但是dirty read可能不是我们想要的 READ COMMITTED:在一个事务中只允许已经commit的记录可见,如果session中select还在查询中,另一session此时insert一条记录,则新添加的数据不可见 REPEATABLE READ:在一个事务开始后,其他session对数据库的修改在本事务中不可见,直到本事务commit或rollback。在一个事务中重复select的结果一样,除非本事务中update数据库。 SERIALIZABLE:最高级别的隔离,只允许事务串行执行。为了达到此目的,数据库会锁住每行已经读取的记录,其他session不能修改数据直到前一事务结束,事务commit或取消时才释放锁。 可以使用如下语句设置MySQL的session隔离级别: 。
Sql代码 。
复制代码代码如下
set transaction isolation level {read uncommitted | read committed | repeatable read | serializable} set transaction isolation level {read uncommitted | read committed | repeatable read | serializable} 。
MySQL默认的隔离级别是REPEATABLE READ,在设置隔离级别为READ UNCOMMITTED或SERIALIZABLE时要小心,READ UNCOMMITTED会导致数据完整性的严重问题,而SERIALIZABLE会导致性能问题并增加死锁的机率 3)事务管理语句: Sql代码 。
复制代码代码如下
START TRANSACTION:开始事务,autocommit设为0,如果已经有一个事务在运行,则会触发一个隐藏的COMMIT COMMIT:提交事务,保存更改,释放锁 ROLLBACK:回滚本事务对数据库的所有更改,然后结束事务,释放锁 SAVEPOINT savepoint_name:创建一个savepoint识别符来ROLLBACK TO SAVEPOINT ROLLBACK TO SAVEPOINT savepoint_name:回滚到从savepoint_name开始对数据库的所有更改,这样就允许回滚事务中的一部分,保证更改的一个子集被提交 SET TRANSACTION:允许设置事务的隔离级别 LOCK TABLES:允许显式的锁住一个或多个table,会隐式的关闭当前打开的事务,建议在执行LOCK TABLES语句之前显式的commit或rollback。我们一般所以一般在事务代码里不会使用LOCK TABLES START TRANSACTION:开始事务,autocommit设为0,如果已经有一个事务在运行,则会触发一个隐藏的COMMIT COMMIT:提交事务,保存更改,释放锁 ROLLBACK:回滚本事务对数据库的所有更改,然后结束事务,释放锁 SAVEPOINT savepoint_name:创建一个savepoint识别符来ROLLBACK TO SAVEPOINT ROLLBACK TO SAVEPOINT savepoint_name:回滚到从savepoint_name开始对数据库的所有更改,这样就允许回滚事务中的一部分,保证更改的一个子集被提交 SET TRANSACTION:允许设置事务的隔离级别 LOCK TABLES:允许显式的锁住一个或多个table,会隐式的关闭当前打开的事务,建议在执行LOCK TABLES语句之前显式的commit或rollback。我们一般所以一般在事务代码里不会使用LOCK TABLES 。
2,定义事务 MySQL默认的行为是在每条SQL语句执行后执行一个COMMIT语句,从而有效的将每条语句独立为一个事务。 在复杂的应用场景下这种方式就不能满足需求了。 为了打开事务,允许在COMMIT和ROLLBACK之前多条语句被执行,我们需要做以下两步(也可以人为是两种方式): 1, 设置MySQL的autocommit属性为0,默认为1 2,使用START TRANSACTION语句显式的打开一个事务(然后autocommit属性会自动被设置为0) 如果已经打开一个事务,则SET autocommit=0不会起作用,因为START TRANSACTION会隐式的提交session中所有当前的更改,结束已有的事务,并打开一个新的事务。 使用SET AUTOCOMMIT语句的存储过程例子: Sql代码 。
复制代码代码如下
delimiter $$ use test$$ create procedure t_insert_table() begin /** 标记是否出错 */ declare t_error int default 0; /** 如果出现sql异常,则将t_error设置为1后继续执行后面的操作 */ declare continue handler for sqlexception set t_error=1; -- 出错处理 /** 显示的开启事务,启动它后,autocommit值会自动设置为0 */ start transaction; insert into t_bom_test(parent_id,child_id) values('C','XXXX'); insert into t_trigger_test(name,age) values('zhangsan',34); /** 标记被改变,表示事务应该回滚 */ if t_error=1 then rollback; -- 事务回滚 else commit; -- 事务提交 end if; end$$ delimiter ; delimiter $$ use test$$ create procedure t_insert_table() begin /** 标记是否出错 */ declare t_error int default 0; /** 如果出现sql异常,则将t_error设置为1后继续执行后面的操作 */ declare continue handler for sqlexception set t_error=1; -- 出错处理 /** 显示的开启事务,启动它后,autocommit值会自动设置为0 */ start transaction; insert into t_bom_test(parent_id,child_id) values('C','XXXX'); insert into t_trigger_test(name,age) values('zhangsan',34); /** 标记被改变,表示事务应该回滚 */ if t_error=1 then rollback; -- 事务回滚 else commit; -- 事务提交 end if; end$$ delimiter ; 。
通常COMMIT或ROLLBACK语句执行时才完成一个事务,但是有些DDL语句等会隐式触发COMMIT,所以应该在事务中尽可能少用或注意一下: Sql代码 。
复制代码代码如下
ALTER FUNCTION ALTER PROCEDURE ALTER TABLE BEGIN CREATE DATABASE CREATE FUNCTION CREATE INDEX CREATE PROCEDURE CREATE TABLE DROP DATABASE DROP FUNCTION DROP INDEX DROP PROCEDURE DROP TABLE UNLOCK TABLES LOAD MASTER DATA LOCK TABLES RENAME TABLE TRUNCATE TABLE SET AUTOCOMMIT=1 START TRANSACTION ALTER FUNCTION ALTER PROCEDURE ALTER TABLE BEGIN CREATE DATABASE CREATE FUNCTION CREATE INDEX CREATE PROCEDURE CREATE TABLE DROP DATABASE DROP FUNCTION DROP INDEX DROP PROCEDURE DROP TABLE UNLOCK TABLES LOAD MASTER DATA LOCK TABLES RENAME TABLE TRUNCATE TABLE SET AUTOCOMMIT=1 START TRANSACTION 。
3,使用Savepoint 使用savepoint回滚难免有些性能消耗,一般可以用IF改写 savepoint的良好使用的场景之一是“嵌套事务”,你可能希望程序执行一个小的事务,但是不希望回滚外面更大的事务: Sql代码 。
复制代码代码如下
CREATE PROCEDURE nested_tfer_funds (in_from_acct INTEGER, in_to_acct INTEGER, in_tfer_amount DECIMAL(8,2)) BEGIN DECLARE txn_error INTEGER DEFAULT 0; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN SET txn_error=1; END SAVEPINT savepint_tfer; UPDATE account_balance SET balance=balance-in_tfer_amount WHERE account_id=in_from_acct; IF txn_error THEN ROLLBACK TO savepoint_tfer; SELECT 'Transfer aborted'; ELSE UPDATE account_balance SET balance=balance+in_tfer_amount WHERE account_id=in_to_acct; IF txn_error THEN ROLLBACK TO savepoint_tfer; SELECT 'Transfer aborted'; END IF: END IF; END; CREATE PROCEDURE nested_tfer_funds (in_from_acct INTEGER, in_to_acct INTEGER, in_tfer_amount DECIMAL(8,2)) BEGIN DECLARE txn_error INTEGER DEFAULT 0; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN SET txn_error=1; END SAVEPINT savepint_tfer; UPDATE account_balance SET balance=balance-in_tfer_amount WHERE account_id=in_from_acct; IF txn_error THEN ROLLBACK TO savepoint_tfer; SELECT 'Transfer aborted'; ELSE UPDATE account_balance SET balance=balance+in_tfer_amount WHERE account_id=in_to_acct; IF txn_error THEN ROLLBACK TO savepoint_tfer; SELECT 'Transfer aborted'; END IF: END IF; END; 。
4,事务和锁 事务的ACID属性只能通过限制数据库的同步更改来实现,从而通过对修改数据加锁来实现。 直到事务触发COMMIT或ROLLBACK语句时锁才释放。 缺点是后面的事务必须等前面的事务完成才能开始执行,吞吐量随着等待锁释放的时间增长而递减。 MySQL/InnoDB通过行级锁来最小化锁竞争。这样修改同一table里其他行的数据没有限制,而且读数据可以始终没有等待。 可以在SELECT语句里使用FOR UPDATE或LOCK IN SHARE MODE语句来加上行级锁 Sql代码 。
复制代码代码如下
SELECT select_statement options [FOR UPDATE|LOCK IN SHARE MODE] SELECT select_statement options [FOR UPDATE|LOCK IN SHARE MODE] 。
FOR UPDATE会锁住该SELECT语句返回的行,其他SELECT和DML语句必须等待该SELECT语句所在的事务完成 LOCK IN SHARE MODE同FOR UPDATE,但是允许其他session的SELECT语句执行并允许获取SHARE MODE锁 死锁: 死锁发生于两个事务相互等待彼此释放锁的情景 当MySQL/InnoDB检查到死锁时,它会强制一个事务rollback并触发一条错误消息 对InnoDB而言,所选择的rollback的事务是完成工作最少的事务(所修改的行最少) Java代码 。
复制代码代码如下
mysql > CALL tfer_funds(1,2,300); ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction 。
死锁在任何数据库系统里都可能发生,但是对MySQL/InnoDB这种行级锁数据库而言可能性相对较少。 可以通过使用一致的顺序来锁row或table以及让事务保持尽可能短来减少死锁的频率。 如果死锁不容易debug,你可以向你的程序中添加一些逻辑来处理死锁并重试事务,但这部分代码多了以后很难维护 所以,比较好的避免死锁的方式是在做任何修改之前按一定的顺序添加行级锁,这样就能避免死锁: Java代码 。
复制代码代码如下
CREATE PROCEDURE tfer_funds3 (from_account INT, to_account INT, tfer_amount NUMERIC(10,2)) BEGIN DECLARE local_account_id INT; DECLARE lock_cursor CURSOR FOR SELECT account_id FROM account_balance WHERE account_id IN (from_account, to_account) ORDER BY account_id FOR UPDATE; START TRANSACTION; OPEN lock_cursor; FETCH lock_cursor INTO local_account_id; UPDATE account_balance SET balance=balance-tfer_amount WHERE account_id=from_account; UPDATE account_balance SET balance=balance+tfer_amount WHERE account_id=to_account; CLOSE lock_cursor; COMMIT; END; 。
设置死锁ttl: innodb_lock_wait_timeout,默认为50秒 如果你在一个事务中混合使用InnoDB和非InnoDB表,则MySQL不能检测到死锁,此时会抛出“lock wait timeuot”1205错误 乐观所和悲观锁策略: 悲观锁:在读取数据时锁住那几行,其他对这几行的更新需要等到悲观锁结束时才能继续 乐观所:读取数据时不锁,更新时检查是否数据已经被更新过,如果是则取消当前更新 一般在悲观锁的等待时间过长而不能接受时我们才会选择乐观锁 悲观锁的例子: Java代码 。
复制代码代码如下
CREATE PROCEDURE tfer_funds (from_account INT, to_account INT,tfer_amount NUMERIC(10,2), OUT status INT, OUT message VARCHAR(30)) BEGIN DECLARE from_account_balance NUMERIC(10,2); START TRANSACTION; SELECT balance INTO from_account_balance FROM account_balance WHERE account_id=from_account FOR UPDATE; IF from_account_balance>=tfer_amount THEN UPDATE account_balance SET balance=balance-tfer_amount WHERE account_id=from_account; UPDATE account_balance SET balance=balance+tfer_amount WHERE account_id=to_account; COMMIT; SET status=0; SET message='OK'; ELSE ROLLBACK; SET status=-1; SET message='Insufficient funds'; END IF; END; 。
乐观锁的例子: Java代码 。
复制代码代码如下
CREATE PROCEDURE tfer_funds (from_account INT, to_account INT, tfer_amount NUMERIC(10,2), OUT status INT, OUT message VARCHAR(30) ) BEGIN DECLARE from_account_balance NUMERIC(8,2); DECLARE from_account_balance2 NUMERIC(8,2); DECLARE from_account_timestamp1 TIMESTAMP; DECLARE from_account_timestamp2 TIMESTAMP; SELECT account_timestamp,balance INTO from_account_timestamp1,from_account_balance FROM account_balance WHERE account_id=from_account; IF (from_account_balance>=tfer_amount) THEN -- Here we perform some long running validation that -- might take a few minutes */ CALL long_running_validation(from_account); START TRANSACTION; -- Make sure the account row has not been updated since -- our initial check SELECT account_timestamp, balance INTO from_account_timestamp2,from_account_balance2 FROM account_balance WHERE account_id=from_account FOR UPDATE; IF (from_account_timestamp1 <> from_account_timestamp2 OR from_account_balance <> from_account_balance2) THEN ROLLBACK; SET status=-1; SET message=CONCAT("Transaction cancelled due to concurrent update", " of account" ,from_account); ELSE UPDATE account_balance SET balance=balance-tfer_amount WHERE account_id=from_account; UPDATE account_balance SET balance=balance+tfer_amount WHERE account_id=to_account; COMMIT; SET status=0; SET message="OK"; END IF; ELSE ROLLBACK; SET status=-1; SET message="Insufficient funds"; END IF; END$$ 。
5,事务设计指南 1,保持事务短小 2,尽量避免事务中rollback 3,尽量避免savepoint 4,默认情况下,依赖于悲观锁 5,为吞吐量要求苛刻的事务考虑乐观锁 6,显示声明打开事务 7,锁的行越少越好,锁的时间越短越好 。
最后此篇关于mysql存储过程事务管理简析的文章就讲到这里了,如果你想了解更多关于mysql存储过程事务管理简析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在使用 PostgREST 将数据库实体暴露给使用这些实体的 Springboot 应用。 我的数据库中有两个实体,分别是 Person 和 City。 我想同时保存 Person 实体和 Cit
1、事务的定义 Redis的事务提供了一种“将多个命令打包, 然后一次性、按顺序地执行”的机制。 redis事务的主要作用就是串联多个命令防止别的命令插队。 但是,事务并不具有传统
SQLite 事务(Transaction) 事务(Transaction)是一个对数据库执行工作单元。事务(Transaction)是以逻辑顺序完成的工作单位或序列,可以是由用户手动操作完成,也可
事务是顺序组操作。 它们作为单个单元运行,并且直到组中的所有操作都成功执行时才终止。 组中的单个故障会导致整个事务失败,并导致对数据库没有影响。 事务符合ACID(原子性,一致性,隔离和耐久性)
我希望将 SqlKata 用于一个项目。但是,项目标准的一部分是查询应该能够作为事务执行。有没有一种方法可以使用 MSSQL 事务执行一个查询或多个查询? 非常感谢。 最佳答案 SQLKata 使用
我只是以多线程方式测试 PetaPoco 事务... 我有一个简单的测试用例: -- 简单的值对象称之为 MediaDevice -- 插入一条记录,更新1000次 void TransactionT
我正在尝试从 Excel VBA 向 SQL 中插入一些数据。 SQL 命令是在 VBA 脚本的过程中构建的,包括使用一些 SQL 变量。 我试图了解事务在 VBA 中是如何工作的,以及它们是否可以处
情况如下: 一个大型生产客户端/服务器系统,其中一个中央数据库表具有某个列,该列的默认值是 NULL,但现在默认值是 0。但是在该更改之前创建的所有行当然仍然具有 null 值,这会在该系统中生成许多
数据库事务是一个熟悉的概念。 try { ... .. updateDB() .. ... commit(); } catch error { rollback(); }
我想了解使用传播支持进行 Spring 交易的用途。 java 文档提到如果具有 @Transactional(propagation = Propagation.SUPPORTS) 的方法从支持该事
我需要获取 hibernate 的事务 ID。对于每笔交易,此 ID 必须是唯一的。我尝试使用 session.getTransaction().hashCode(),但我相信这个值不是唯一的。 最佳
我从 firebase 收到以下消息:runTransactionBlock:启用持久性时检测到的使用情况。请注意,事务不会在应用重新启动后保留。 那么应用程序重新启动后到底会发生什么?由于主数据库的
我需要在 jdbc 中执行选择、更新、插入查询的序列。 这是我的代码: public String editRequest(){ connection = DatabaseUtil.getServi
Java 是否提供了一种智能“聚合”事务的方法?如果我有多个异构数据存储库,我想保持同步(即用于数据的 Postgres、用于图表的 Neo4j 以及用于索引的 Lucene),是否有一个范例仅允许
我对标题中的主题有几个问题。首先,假设我们使用 JDBC,并且有 2 个事务 T1 和 T2。在 T1 中,我们在一个特定的行上执行 select 语句。然后我们对该行执行更新。在事务 T2 中,我们
我有一个 Python CGI 处理支付交易。当用户提交表单时,CGI 被调用。提交后,CGI 需要一段时间才能执行信用卡交易。在此期间,用户可能会按下 ESC 或刷新按钮。这样做不会“杀死”CGI,
我有一个代码,类似这样 def many_objects_saving(list_of_objects): for some_object in list_of_objects:
我有一个包含 100,000 条记录的表。我正在考虑使用事务来更新数据。将有一个查询将一列更新为零,并且大约有 5000 个更新,每个更新将更新一条记录。 这些大型事务对内存有何影响?事务运行时选择数
有没有办法在一个命令中执行 SQL 事务?例如 mysql_query(" START TRANSACTION; INSERT INTO table1 ....etc; INSERT INTO tab
真心希望能帮到你! 我使用以下函数在 PHP/MySql 应用程序中发送消息: public function sendMail($sender_id, $recipient_id, $subject
我是一名优秀的程序员,十分优秀!