关灯
开启左侧

JDBC处理事务

[复制链接]
秋名山车神 发表于 2018-10-30 22:24:10 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
 
一、什么是事务?
  在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
二、事务是必须满足4个条件(ACID)
  • 事务的原子性( Atomicity):一组事务,要么成功;要么撤回。
  • 一致性 (Consistency):事务执行后,数据库状态与其他业务规则保持一致。如转账业务,无论事务执行成功否,参与转账的两个账号余额之和应该是不变的。
  • 隔离性(Isolation):事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。
  • 持久性(Durability):软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit 选项 决定什么时候吧事务保存到日志里。
三、MySQL中的事务
    在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。
  • 开启事务:start transaction
  • 结束事务:commit或rollback
     在执行SQL语句之前,先执行start transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条SQL语句所作出的影响会持久到数据库中,或者rollback,表示回滚到事务的起点,之前做的所有操作都被撤销了。
  1. mysql> SELECT * FROM account;
  2. +----+------+---------+
  3. | id | NAME | balance |
  4. +----+------+---------+
  5. |  1 | zs   | 1000.00 |
  6. |  2 | ls   | 1000.00 |
  7. |  3 | ww   | 1000.00 |
  8. +----+------+---------+
  9. 3 rows in set (0.00 sec)

  10. mysql> START TRANSACTION;
  11. Query OK, 0 rows affected (0.00 sec)

  12. mysql> UPDATE account SET balance=900 WHERE name = 'zs';
  13. Query OK, 1 row affected (0.00 sec)
  14. Rows matched: 1  Changed: 1  Warnings: 0

  15. mysql> SELECT * FROM account;
  16. +----+------+---------+
  17. | id | NAME | balance |
  18. +----+------+---------+
  19. |  1 | zs   |  900.00 |
  20. |  2 | ls   | 1000.00 |
  21. |  3 | ww   | 1000.00 |
  22. +----+------+---------+
  23. 3 rows in set (0.00 sec)

  24. mysql> UPDATE account SET balance=1100 WHERE name = 'ls';
  25. Query OK, 1 row affected (0.00 sec)
  26. Rows matched: 1  Changed: 1  Warnings: 0

  27. mysql> SELECT * FROM account;
  28. +----+------+---------+
  29. | id | NAME | balance |
  30. +----+------+---------+
  31. |  1 | zs   |  900.00 |
  32. |  2 | ls   | 1100.00 |
  33. |  3 | ww   | 1000.00 |
  34. +----+------+---------+
  35. 3 rows in set (0.00 sec)

  36. mysql> ROLLBACK;
  37. Query OK, 0 rows affected (0.00 sec)

  38. mysql> SELECT * FROM account;
  39. +----+------+---------+
  40. | id | NAME | balance |
  41. +----+------+---------+
  42. |  1 | zs   | 1000.00 |
  43. |  2 | ls   | 1000.00 |
  44. |  3 | ww   | 1000.00 |
  45. +----+------+---------+
  46. 3 rows in set (0.00 sec)

  47. mysql> START TRANSACTION;
  48. Query OK, 0 rows affected (0.00 sec)

  49. mysql> UPDATE account SET balance=balance-100 WHERE name = 'zs';
  50. Query OK, 1 row affected (0.00 sec)
  51. Rows matched: 1  Changed: 1  Warnings: 0

  52. mysql> SELECT * FROM account;
  53. +----+------+---------+
  54. | id | NAME | balance |
  55. +----+------+---------+
  56. |  1 | zs   |  900.00 |
  57. |  2 | ls   | 1000.00 |
  58. |  3 | ww   | 1000.00 |
  59. +----+------+---------+
  60. 3 rows in set (0.00 sec)

  61. mysql> UPDATE account SET balance=balance+100 WHERE name = 'ls';
  62. Query OK, 1 row affected (0.00 sec)
  63. Rows matched: 1  Changed: 1  Warnings: 0

  64. mysql> SELECT * FROM account;
  65. +----+------+---------+
  66. | id | NAME | balance |
  67. +----+------+---------+
  68. |  1 | zs   |  900.00 |
  69. |  2 | ls   | 1100.00 |
  70. |  3 | ww   | 1000.00 |
  71. +----+------+---------+
  72. 3 rows in set (0.00 sec)

  73. mysql> commit;
  74. Query OK, 0 rows affected (0.02 sec)

  75. mysql> SELECT * FROM account;
  76. +----+------+---------+
  77. | id | NAME | balance |
  78. +----+------+---------+
  79. |  1 | zs   |  900.00 |
  80. |  2 | ls   | 1100.00 |
  81. |  3 | ww   | 1000.00 |
  82. +----+------+---------+
  83. 3 rows in set (0.00 sec)
复制代码
四、JDBC事务
在JDBC中处理事务,都是通过Connection完成的。
同一事务中所有的操作,都在使用同一个Connection对象。
①JDBC中的事务   
Connection的三个方法与事务有关:
  • setAutoCommit(boolean):设置是否为自动提交事务,如果true(默认值为true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务,如果设置为false,那么相当于开启了事务了;con.setAutoCommit(false) 表示开启事务。
  • commit():提交结束事务。
  • rollback():回滚结束事务。
JDBC处理事务的代码格式:
  1. try{
  2.      con.setAutoCommit(false);//开启事务
  3.      ......
  4.      con.commit();//try的最后提交事务      
  5. } catch() {
  6.     con.rollback();//回滚事务
  7. }
复制代码
示例:
  1. public class AccountDao {
  2.     /*
  3.     * 修改指定用户的余额
  4.     * */
  5.     public void updateBalance(Connection con, String name,double balance) {
  6.         try {
  7.             String sql = "UPDATE account SET balance=balance+? WHERE name=?";
  8.             PreparedStatement pstmt = con.prepareStatement(sql);
  9.             pstmt.setDouble(1,balance);
  10.             pstmt.setString(2,name);
  11.             pstmt.executeUpdate();
  12.         }catch (Exception e) {
  13.             throw new RuntimeException(e);
  14.         }
  15.     }
  16. }
复制代码
  1. import cn.itcast.jdbc.JdbcUtils;
  2. import org.junit.Test;
  3. import java.sql.Connection;
  4. import java.sql.SQLException;

  5. public class Demo1 {
  6.     /*
  7.     * 演示转账方法
  8.     * 所有对Connect的操作都在Service层进行的处理
  9.     * 把所有connection的操作隐藏起来
  10.     * */
  11.     public void transferAccounts(String from,String to,double money) {
  12.         //对事务的操作
  13.         Connection con = null;
  14.         try{
  15.             con = JdbcUtils.getConnection();
  16.             con.setAutoCommit(false);
  17.             AccountDao dao = new AccountDao();
  18.             dao.updateBalance(con,from,-money);//给from减去相应金额
  19.             if (true){
  20.                 throw new RuntimeException("不好意思,转账失败");
  21.             }
  22.             dao.updateBalance(con,to,+money);//给to加上相应金额
  23.             //提交事务
  24.             con.commit();

  25.         } catch (Exception e) {
  26.             try {
  27.                 con.rollback();
  28.             } catch (SQLException e1) {
  29.                 e.printStackTrace();
  30.             }
  31.             throw new RuntimeException(e);
  32.         }
  33.     }
  34.     @Test
  35.     public void fun1() {
  36.         transferAccounts("zs","ls",100);
  37.     }
  38. }
复制代码
五、事务隔离级别
1、事务的并发读问题
  • 脏读:读取到另外一个事务未提交数据(不允许出来的事);
  • 不可重复读:两次读取不一致;
  • 幻读(虚读):读到另一事务已提交数据。
2、并发事务问题
因为并发事务导致的问题大致有5类,其中两类是更新问题三类是读问题。
  • 脏读(dirty read):读到另一个事务的未提交新数据,即读取到了脏数据;
  • 不可重复读(unrepeatable):对同一记录的两次读取不一致,因为另一事务对该记录做了修改;
  • 幻读(虚读)(phantom read):对同一张表的两次查询不一致,因为另一事务插入了一条记录。
3、四大隔离级别
    4个等级的事务隔离级别,在相同的数据环境下,使用相同的输入,执行相同的工作,根据不同的隔离级别,可以导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力是不同的。
1、SERIALIZABLE(串行化)
  • 不会出现任何并发问题,因为它是对同一数据的访问是串行的,非并发访问的;
  • 性能最差
2、REPEATABLE READ(可重复读)(MySQL)
  • 防止脏读和不可重复读,不能处理幻读
  • 性能比SERIALIZABLE好
3、READ COMMITTED(读已提交数据)(Oracle)
  • 防止脏读,不能处理不可重复读和幻读;
  • 性能比REPEATABLE READ好
4、READ UNCOMMITTED(读未提交数据)
  • 可能出现任何事物并发问题,什么都不处理。
  • 性能最好
六、MySQL隔离级别
MySQL的默认隔离级别为Repeatable read,可以通过下面语句查看:
  1. SELECT @@`TX_ISOLATION`;
复制代码
也可以通过下面语句来设置当前连接的隔离级别:
  1. SET TRANSACTION ISOLATION LEVEL REPEATABLE READ ;//[4选1]
复制代码
七、JDBC设置隔离级别
con.setTransactionIsolation(int level) :参数可选值如下:
  • Connection.TRANSACTION_READ_UNCOMMITTED;
  • Connection.TRANSACTION_READ_COMMITTED;
  • Connection.TRANSACTION_REPEATABLE_READ;
  • Connection.TRANSACTION_READ_SERIALIZABLE。

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

排行榜
关闭

站长推荐上一条 /1 下一条

官方微信

全国服务热线:

400-0708-360

公司地址:国家西部信息安全产业基地(成都市高新区云华路333号)

邮编:610000    Email:2908503813@qq.com

Copyright   ©2015-2016  EOIT论坛Powered by©Discuz!    ( 蜀ICP备11000634号-7 )