logo资料库

北邮 数据库系统原理(SQL Server版) 实验七.pdf

第1页 / 共7页
第2页 / 共7页
第3页 / 共7页
第4页 / 共7页
第5页 / 共7页
第6页 / 共7页
第7页 / 共7页
资料共7页,全文预览结束
实验七 数据库的事务创建与运行实验
实验目的
实验内容与要求
实验总结
实验七 数据库的事务创建与运行实验 实验目的 通过实验,了解 SQL Server 数据库系统中各类数据库事务的定义机制和基于锁的并发控 制机制,掌握 QL Server 数据库系统的事务控制机制。 实验内容与要求 1.定义三种模式的数据库事务 事务是单个工作单元。 如果某一事务成功,则在该事务中进行的所有数据修改均会提交, 成为数据库中的永久组成部分。 如果事务遇到错误且必须取消或回滚,则所有数据修改均 被清除。 SQL Server 中主要有以下三种事务: i.自动提交事务 每条单独的语句都是一个事务。 ii.显式事务 每个事务均以 BEGIN TRANSACTION 语句显式开始,以 COMMIT 或 ROLLBACK 语句显式 结束。 iii.隐式事务 在前一个事务完成时新事务隐式启动,但每个事务仍以 COMMIT 或 ROLLBACK 语句显式 完成。 首先创建三种事务:显示事务、隐式事务和自动提交事务。 自动提交事务: INSERT INTO student VALUES('g9950404', 'Mike', '男', '1998-02-04', 'g99504', '2015-09-12', '江苏省南京市'); 显示事务: --使电磁波工程的总学时加一,同时网络技术与实践的总学时减一 BEGIN TRANSACTION; UPDATE course SET total_perior = total_perior + 1 WHERE course_id = 'dep01_s001'; UPDATE course SET total_perior = total_perior - 1 WHERE course_id = 'dep01_s002'; COMMIT; 隐式事务: --使电磁波工程的周学时加二,同时网络技术与实践的周学时减二 UPDATE course SET week_perior = week_perior + 2 WHERE course_id = 'dep01_s001'; UPDATE course SET week_perior = week_perior - 2 WHERE course_id = 'dep01_s002'; COMMIT; (1)启动显式事务; 启动事务之前的内容: 启动事务:
--使电磁波工程的总学时加一,同时网络技术与实践的总学时减一 BEGIN TRANSACTION; UPDATE course SET total_perior = total_perior + 1 WHERE course_id = 'dep01_s001'; UPDATE course SET total_perior = total_perior - 1 WHERE course_id = 'dep01_s002'; COMMIT; 事务执行结果: 对比启动事务之前的内容,可以发现事务成功的执行了,结果与预期一致。 (2)在事务内设置保存点; 为了提高事务执行的效率或者进行程序的调试等,可以在事务的某一点处设置一个标 记,这样当使用回滚语句时可以不用回滚到事务的起始位置,而是回滚到标记所在的位置(即 保存点)。 --使电磁波工程的总学时加一,同时网络技术与实践的总学时减一 BEGIN TRANSACTION; UPDATE course SET total_perior = total_perior + 1 WHERE course_id = 'dep01_s001'; SAVE TRANSACTION point1; --保存点 UPDATE course SET total_perior = total_perior - 1 WHERE course_id = 'dep01_s002'; ROLLBACK TRANSACTION point1; --回滚事务 COMMIT; 这是执行事务之前的内容: 这是执行事务之后的内容: 对比发现:电磁波工程的总学时和网络技术与实践的总学时并没有同步更新。这是因为 保存点的作用,事务的回滚只是回到保存点,而第一条更新语句的结果依然存在,与预期的 结果相符合。 (3)启动隐式事务模式; --使电磁波工程的周学时加二,同时网络技术与实践的周学时减二 SET IMPLICIT_TRANSACTIONS ON; --启动隐式事务 UPDATE course SET week_perior = week_perior + 2 WHERE course_id = 'dep01_s001'; UPDATE course SET week_perior = week_perior - 2 WHERE course_id = 'dep01_s002'; COMMIT; SET IMPLICIT_TRANSACTIONS OFF; --关闭隐式事务 执行事务之前的内容: 执行结果:
对比之前的内容:电磁波工程的周学时加二,同时网络技术与实践的周学时减二。与预 期的结果相符合。 (4)设置事务的隔离级别为重复读。 重复读:指定语句不能读取已由其他事务修改但尚未提交的行,并且指定,其他任何事 务都不能在当前事务完成之前修改由当前事务读取的数据。也就是说:对事务中的每个语句 所读取的全部数据都设置共享锁,并且该共享锁一直保持到事务完成为止。 --设置事务隔离级别为重复读 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; 2.察看事务的锁信息和隔离级别 --查看事务隔离级别 DBCC Useroptions 什么是锁?锁用于多用户环境下保证数据库完整性和一致性。 --查看事务锁信息 SELECT * from sys.dm_tran_locks; 3.利用 SQL 语句和数据库 API 函数控制事务。 使用 SQL 语句: --将无线电系的老师转10个到通信系 BEGIN TRANSACTION ex_teacher --开始事务 DECLARE @tran_error int; SET @tran_error = 0; BEGIN TRY UPDATE department SET teacher_num = teacher_num - 10 WHERE department_id = 'dep_01'; SET @tran_error = @tran_error + @@ERROR; --测试出错代码,看无线电系的老师减少,通信系的老师是否会增加 --SET @tran_error = 1;
UPDATE department SET teacher_num = teacher_num + 10 WHERE department_id = 'dep_02' SET @tran_error = @tran_error + @@ERROR; END TRY BEGIN CATCH PRINT '出现异常:' + error_message(); SET @tran_error = @tran_error + 1; END CATCH IF(@tran_error > 0) BEGIN --执行出错,回滚事务 ROLLBACK TRANSACTION; PRINT '执行失败'; END ELSE BEGIN --没有异常,提交事务 COMMIT TRANSACTION; END 执行前: 执行后: 使用 API 函数: 以下代码把电子工程系的教师数量减少 5 个: #include #include #include #include #include #include SQLRETURN retcode; //结果返回集 SQLHDBC conn; //数据库连接句柄 SQLHSTMT stmt; //定义语句句柄 SQLHENV env; //环境参数变量 //执行SQL语句 void SQL(SQLCHAR query[]) { retcode = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
printf("%s\n", query); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { //处理数据 retcode = SQLExecDirect(stmt, query, SQL_NTS); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { SQLFreeHandle(SQL_HANDLE_STMT, stmt); } } else { printf("Could not perform your transaction.\n"); } } int main() { //分配环境句柄 retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { //设置环境属性 retcode = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { //分配连接句柄 retcode = SQLAllocHandle(SQL_HANDLE_DBC, env, &conn); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { //连接 retcode = SQLDriverConnect(conn, NULL, (SQLCHAR*)"DRIVER={SQL Server};SERVER=SARKAR\\SQLEXPRESS;DATABASE=学生选课;UID=nicholas;PWD=nicholas;", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE); NULL); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { printf("Connected to database!\n"); //获取事务自动提交状态 SQLINTEGER autoCommitState; SQLGetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, &autoCommitState, 0, printf("autoCommit is set to : %d\n", autoCommitState); //关闭自动提交 printf("Disabling autoCommit......\n"); retcode = SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, SQL_NTS); 0, NULL); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { //再次获取事务自动提交状态 SQLGetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, &autoCommitState, printf("autoCommit is set to : %d\n", autoCommitState); //执行SQL语句
SQLCHAR update1[] = "UPDATE department SET teacher_num = teacher_num - 5 WHERE department_id = 'dep_03'"; { SQL(update1); //由于自动提交已关闭,因此需要在断开连接之前手动提交事务 printf("Committing transaction.\n"); retcode = SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) } printf("Trasaction committed.\n"); //SQLFreeConnect(conn); //释放连接句柄 else printf("Error commit trasaction.\n"); } else { printf("Counld not disable autoCommit.\n"); exit(EXIT_FAILURE); } } else printf("Connection error!!!"); } SQLFreeHandle(SQL_HANDLE_DBC, conn); //释放连接句柄 } SQLFreeEnv(env); //释放SQL环境句柄 } system("pause"); return 0; } 执行前: 代码执行结果:
执行代码后数据内容: 对比执行前的数据内容可以知道:事务成功执行,电子工程系的老师数量减少了 5 个。 实验总结 在实验中有哪些重要问题或者事件?你如何处理的?你的收获是什么?有何建议和意 见等等。 这次实验式数据库的事务实验,最开始我并不清楚什么是事务。通过查阅资料才发现事 务的一个显著特点就是:原子性。就是说,一个事务里面的操作,要么全部执行成功,要么 全部执行失败。然后我知道了三种事务之间的区别,知道了什么是保存点,什么是事务的隔 离级别以及事务锁。事务的隔离级别和锁是密切相关的,锁的一个重要作用就是保证数据库 数据的一致性和完整性。 实验的最后一部分要求我们用分别用 SQL 语句和 API 函数来控制事务。用 SQL 语句很好 控制,毕竟前边的内容用的都是 SQL 语句。由于前面有一个用 ODBC 连接 SQL Server 的实验, 自然就想到继续用 ODBC 来进行事务的操作。但微软关于 SQL Server 的相关文档并没有给出 明确的示例程序,然后我查阅了大量的参考资料,最终搞清楚了如何用 ODBC 来控制事务。 总之,完整的做完了这次的实验,收获满满。
分享到:
收藏