JAVA WEB -事务处理
来源:互联网 发布:三文鱼部位图解知乎 编辑:程序博客网 时间:2024/06/01 18:53
1.事务处理
1.1 事务处理类型
mysql
JDBC
DBUtils
1.2 Mysql事务处理
首先,打开小海豚,创建表,并输入数据。
CREATE TABLE account( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(50), money DOUBLE);INSERT INTO account(id,NAME,money) VALUES(NULL,'jack',10000);INSERT INTO account(id,NAME,money) VALUES(NULL,'rose',20000);
打开CMD,进行操作
Start transaction;
commit;
roll back;
三个步骤,如果打开Start transaction,并且Update数据库中的数据,在小海豚刷新是没有任何变化的,执行commit后,刷新小海豚数据才会更新。’
1.3 mysql autocommit
每次在CMD中操作mysql语句,都是默认autocommit。
可以通过语句进行改变:show variables like ‘xxcommit’; —-》
–》 set autocommit = 0/1;
***Oracle 数据库不自动commit;
1.4 JDBC事务操作
conn.setAutoCommit(false) 开启事务
conn.commit() 提交事务
conn.rollbalck() 回滚事务
@Test public void demo0() throws Exception{ Connection connection = null; PreparedStatement preparedStatement = null; try { connection = (Connection) JDBCUtils.getConnection(); connection.setAutoCommit(false); String sql = "update account set money = money + ? where name = ?"; preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1,-100); preparedStatement.setString(2, "zhilong"); preparedStatement.executeUpdate(); preparedStatement.setInt(1,100); preparedStatement.setString(2, "tommy"); preparedStatement.executeUpdate(); connection.commit(); int r = preparedStatement.executeUpdate(); System.out.println(r); } catch (Exception e) { // TODO: handle exception try { connection.rollback(); throw new RuntimeException("program error",e); } catch (Exception e2) { // TODO: handle exception } }finally { if (connection != null) { connection.close(); } } }
1.5 DBUtils事务操作
*conn.setAutoCommit(false) 开启事务
*new QueryRunner() 创建核心类,不设置数据源,手动管理连接。
*Query()、Update() 手动传递连接
*Dbutils.commitAndClose(conn) 或 DbUtils.rollbackandClose(conn) 关闭连接。
Connection connection = null; QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource()); try { connection = C3P0Utils.getConnection(); connection.setAutoCommit(false); String sql = "update account set money= money+? where name = ?"; Object[] params = {-100,"jack"}; int r = queryRunner.update(connection, sql, params); Object[] params2 = {100,"rose"}; int r2 = queryRunner.update(connection, sql, params2);// DbUtils.commitAndClose(connection); DbUtils.commitAndCloseQuietly(connection); } catch (Exception e) { // TODO: handle exception DbUtils.rollbackAndClose(connection); }
1.6 分层
dao 数据库操作
Service 业务代码加上事务进行操作
domain Bean层
AccountDao:
public class AccountDao { public void out(Connection conn,String outUser,Double money) throws Exception{ QueryRunner queryRunner = new QueryRunner(); String sql = "update account set money = money - ? where name = ?"; Object[] objects = {money,outUser}; int r = queryRunner.update(conn,sql, objects); System.out.println(r); } public void in(Connection connection,String inUser,Double money) throws Exception{ QueryRunner queryRunner = new QueryRunner(); String sql = "update account set money = money - ? where name = ?"; Object[] objects = {money,inUser}; queryRunner.update(connection,sql,objects); }}
AccountService:
public class AccountService { public void transfer(String outUser,String inUser,double money) throws Exception{// 1,获得连接 Connection connection = C3P0Utils.getConnection(); try {// 2开启事务 connection.setAutoCommit(false);// 业务代码 AccountDao accountDao = new AccountDao(); accountDao.out(connection,outUser, money); accountDao.in(connection,inUser, money);// 3提交事务 DbUtils.commitAndCloseQuietly(connection); } catch (Exception e) { // TODO: handle exception// 如果有异常就回滚 DbUtils.rollbackAndCloseQuietly(connection); throw new RuntimeException(e); } }}
Test:
public class test { public static void main(String[] args) throws Exception { String outUser = "jack"; String inUser = "rose"; double money = 100d; try { AccountService accountService = new AccountService(); accountService.transfer(outUser, inUser, money); System.out.println("transfer successfully"); } catch (Exception e) { // TODO: handle exception System.out.println("transfer failed"); } }}
####1.7 ThreadLocal
用途:除了事务以外,JDK允许此类可以在一个线程中共享数据。
Threadlocal:底层就是一个Map,key存放的是当前线程,Value存放的是共享数据。
实现:C3P0Utils.getConnection() 内部使用Threadlocal,用于本地线程缓存连接,1).从ThreadLocal获得连接
2).如果没有,从连接池获得连接,并保存到ThreadLocalhost中。
3).获得连接,返回即可。
代码:
**C3P0Utils:**public class C3P0Utils { private static DataSource dataSource = new ComboPooledDataSource("itheima"); private static ThreadLocal<Connection> local = new ThreadLocal<Connection>(); public static ComboPooledDataSource getDataSource(){ return (ComboPooledDataSource) dataSource; } public static Connection getConnection() throws SQLException{// 1.从本地线程变量获得 Connection connection = local.get();// 2.如果没有,从连接池获得,并添加到ThreadLocal中 if (connection == null) { connection = dataSource.getConnection(); local.set(connection); } return connection; }}
AccountService
public class AccountService { public void transfer(String outUser,String inUser,double money) throws Exception{ java.sql.Connection connection = null; try {// 获得连接 connection = C3P0Utils.getConnection();// 开启事务 connection.setAutoCommit(false);// 业务操作 AccountDao accountDao = new AccountDao(); accountDao.out(outUser, money); accountDao.in(inUser, money);// 提交事务 DbUtils.commitAndCloseQuietly(connection); } catch (Exception e) { // TODO: handle exception DbUtils.rollbackAndCloseQuietly(connection); throw new RuntimeException(e); } }}
AccountDao
public void out(String outUser,Double money) throws Exception{ QueryRunner queryRunner = new QueryRunner(); String sql = "update account set money = money - ? where name = ?"; Object[] objects = {money,outUser}; int r = queryRunner.update(C3P0Utils.getConnection(), sql,objects); System.out.println(r); } public void in(String inUser,Double money) throws Exception{ QueryRunner queryRunner = new QueryRunner(); String sql = "update account set money = money - ? where name = ?"; Object[] objects = {money,inUser}; queryRunner.update(C3P0Utils.getConnection(),sql,objects); }}
Test
public class test { public static void main(String[] args) { String outUser = "zhilong"; String inUser = "tommy"; double money = 100d; try { AccountService accountService = new AccountService(); accountService.transfer(outUser, inUser, money); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } }}
1.7 事务总结
*1.7.1 事务特性:ACID
原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作,要么都发生,要么都不发生。
一致性(Consistency)事务前后数据的完整性必须保持一致。
隔离型(Isolation)事务的隔离性是指多个用户并发访问数据时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离。
持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中的数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
*1.7.2并发访问问题
如果不考虑隔离性,事务存在3种并发访问问题。
脏读:一个事务读到另一个事务未提交的数据。
不可重复读:一个事务读到另一个事务已经提交的(Update)数据,引发另一个事务,在事务中多次查询结果不一致。
虚读和幻读:一个事务读到另一个事务已经提交的(insert)数据,导致另一个事务,在事务中多次查询结果不一致。
*1.7.3隔离级别:解决问题
Read uncommitted 读未提交,一个事务读到另一个事务没有提交的数据。存放,3个问题(脏读,不可重复读,虚读)。
解决,0个问题。
Read committed 读已提交,一个事务读到另一个事务已提交的数据。
存放:2个问题(不可重复读,虚读)
解决:1个问题(脏读)。
repeatable Read:可重复读,在一个事务中读到数据始终保持一致,无论另一个事务是否提交。
存放:1个问题(虚读)。
解决:2个问题(脏读,不可重复读)。
serializable 串行化,同时只能执行一个事务,相当于事务中的单线程。
存放:0个问题。
解决:1个问题(脏读,不可重复读,虚读)。
安全和性能对比
安全性:serializable>repeatable read>read committed>read uncommitted.
性能:serializable
A: mysql> select * from accoun+----+---------+-------+| id | name | money |+----+---------+-------+| 1 | jack | 25400 || 2 | rose | 20000 || 3 | zhilong | 9300 || 4 | Tommy | 5100 || 5 | Tommy | 5000 || 6 | hans | 4600 |+----+---------+-------+6 rows in set (0.00 sec)mysql> select * from accoun+----+---------+-------+| id | name | money |+----+---------+-------+| 1 | jack | 25300 || 2 | rose | 20000 || 3 | zhilong | 9300 || 4 | Tommy | 5100 || 5 | Tommy | 5000 || 6 | hans | 4600 |+----+---------+-------+6 rows in set (0.00 sec)mysql> select * from accoun+----+---------+-------+| id | name | money |+----+---------+-------+| 1 | jack | 25400 || 2 | rose | 20000 || 3 | zhilong | 9300 || 4 | Tommy | 5100 || 5 | Tommy | 5000 || 6 | hans | 4600 |+----+---------+-------+6 rows in set (0.00 sec)B:mysql> select * from accoun+----+---------+-------+| id | name | money |+----+---------+-------+| 1 | jack | 25400 || 2 | rose | 20000 || 3 | zhilong | 9300 || 4 | Tommy | 5100 || 5 | Tommy | 5000 || 6 | hans | 4600 |+----+---------+-------+6 rows in set (0.00 sec)mysql> select * from accoun+----+---------+-------+| id | name | money |+----+---------+-------+| 1 | jack | 25300 || 2 | rose | 20000 || 3 | zhilong | 9300 || 4 | Tommy | 5100 || 5 | Tommy | 5000 || 6 | hans | 4600 |+----+---------+-------+6 rows in set (0.00 sec)mysql> select * from accoun+----+---------+-------+| id | name | money |+----+---------+-------+| 1 | jack | 25400 || 2 | rose | 20000 || 3 | zhilong | 9300 || 4 | Tommy | 5100 || 5 | Tommy | 5000 || 6 | hans | 4600 |+----+---------+-------+6 rows in set (0.00 sec)
>读已提交
A窗口设置隔离级别
AB同时开启事务
A查询
B更新、但不提交
A在查询?–数据不变,解决问题【脏读】。
B提交。
A在查询?–数据改变,存在问题【不可重复读】。
>可重复读:repeatable Read
A窗口设置隔离级别
AB同时开启事务
A查询
B更新,但不提交
A在查询
B提交
A在查询?—数据不变,解决【脏读】
B提交
A在查询? —数据不变,解决【不可重复读】
A提交或者回滚
A在查询 ?—数据改变,另一个事务【可重复读】
>串行化:serializable
A窗口设置隔离级别
AB同时开启事务
A查询
B跟新?–等待更新,如果A没有进一步操作,B将等待超时
A回滚
B窗口?–可以继续操作,等待结束。
- JAVA WEB -事务处理
- java 事务处理
- java事务处理
- Java事务处理
- Java事务处理
- java 事务处理
- Java 事务处理
- java事务处理
- java事务处理
- JAVA 事务处理
- java事务处理
- java事务处理
- java事务处理
- java事务处理
- Java事务处理
- java事务处理
- Java事务处理
- java事务处理
- 第一节 scala 变量的定义和使用
- 04_Qt的画笔、作画和自定义控件
- 76. Minimum Window Substring 10-line template that can solve most 'substring' problems
- <java EE 项目:petstore> 从一个简单项目看 java web 如何在本jsp页面上对用户输入的格式进行限制与验证
- CANopen 块传输通信详解
- JAVA WEB -事务处理
- java泛型之桥方法
- 关于Fragment的一些使用心得-跳转和返回栈实战浅析
- iOS 表格数据刷新
- 生活在智慧龙岗的居民究竟有多幸福?
- SpringMVC+Spring+Mybatis整合配置
- SSD 之OP预留空间
- elasticsearch windows下安装
- iOS 探讨之 动态行为 UIDynamicItem