1.事务
事务是指一组逻辑操作单元,使数据从一种状态变换到另一种状态。
为确保数据库中数据的一致性,数据的操纵应当是离散的成组的逻辑单元:当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分
操作失败,整个事务应全部视为错误,所有从起始点以后的操作应全部回退到开始状态。
事务的操作:
1.先定义开始一个事务,然后对数据作修改操作,
2.这时如果提交(COMMIT),这些修改就永久地保存下来,
3.如果回退(ROLLBACK),数据库管理系统将放弃所作的所有修改而回到开始事务时的状态。
2.事务的ACID(acid)属性
1. 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2. 一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
3. 隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4. 持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
3.JDBC 事务处理
MySQL命令,事务的用法:
l。开启事务(start transaction)
2.执行sql操作(普通sql操作)
3.提交/回滚(commit/rollback)
注意:
建表的时候,选择 Innodb引擎才支持事务
默认情况下,MySQL是自动提交事务,每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。如果某一组操作需要在一个事务中,那么需要使用start transaction,一旦rollback或commit就结束当次事务。
如果需要在当前会话的整个过程中都取消自动提交事务,进行手动提交事务,就需要设置set autocommit = false;或set autocommit = 0;那样的话每一句SQL都需要手动commit提交才会真正生效。rollback或commit之前的所有操作都视为一个事务。
JDBC程序中当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
JDBC程序中为了让多个 SQL 语句作为一个事务执行:(重点)
调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务
在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
在其中某个操作失败或出现异常时,调用 rollback(); 方法回滚事务
若此时 Connection 没有被关闭, 则需要恢复其自动提交状态 setAutoCommit(true);
注意:
如果多个操作,每个操作使用的是自己单独的连接,则无法保证事务。即同一个事务的多个操作必须在同一个连接下
4.数据库的隔离级别
1.脏读2.不可重复读3.幻读4.序列化
对于同时运行的多个事务(多线程并发), 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致
各种并发问题: (问题的本质就是线程安全问题,共享数据的问题)
1.脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是
临时且无效的.
2.不可重复读: 对于两个事务 T1, T2, T1 读取了一个字段, 然后 T2 更新并提交了该字段. 之后, T1再次读取同一个字段,
值就不同了.
3.幻读: 对于两个事务 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果
T1 再次读取同一个表, 就会多出几行.
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题. 一个事务与其他事
务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好,
但并发性越弱。
Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE. Oracle 默认的事务隔离级别为: READ COMMITED
Mysql 支持 4 中事务隔离级别. Mysql 默认的事务隔离级别为: REPEATABLE READ
每启动一个 mysql 程序, 就会获得一个单独的数据库连接. 每个数据库连接都有一个全局变量 @@tx_isolation,
表示当前的事务隔离级别. MySQL 默认的隔离级别为 Repeatable Read
1.查看当前的隔离级别: SELECT @@tx_isolation;
2.设置当前 mySQL 连接的隔离级别: set transaction isolation level read committed;
3.设置数据库系统的全局的隔离级别: set global transaction isolation level read committed;
JDBC可以通过Connection对象的:
1.int getTransactionIsolation():获取此 Connection 对象的当前事务隔离级别
2.void setTransactionIsolation(int level):试图将此 Connection 对象的事务隔离级别更改为给定的级别。
可能的事务隔离级别是 Connection 接口中定义的常量。
level - 以下 Connection 常量之一:
1.Connection.TRANSACTION_READ_UNCOMMITTED(=1)
2.Connection.TRANSACTION_READ_COMMITTED(=2)、
3.Connection.TRANSACTION_REPEATABLE_READ(=4)
4.Connection.TRANSACTION_SERIALIZABLE(=8)。
(注意,不能使用 Connection.TRANSACTION_NONE(=0),因为它指定了不受支持的事务。)
注意:INNODB使用了MVCC (Multiversion Concurrency Control),即多版本并发控制技术防止幻读。
MVCC主要是为Repeatable-Read事务隔离级别做的。
但是InnoDB的可重复读隔离级别和其他数据库的可重复读是有区别的,不会造成幻象读(phantom read)。
说明:
脏读:客户端A却读取到B未提交的脏数据
不可重复读:在一个事务中前后两次读取的结果值并不一致,导致了不可重读读
幻读:重点在于新增或者删除(数据条数的变化):同样条件下,第一次和第二次读出来的记录条数不一样
脏读、不可重读度、幻读,其实都是数据库的一致性问题,必须由一定的事务隔离机制来解决
MySQL 默认的级别是:Repeatable read 可重复读。
5.锁
行级锁:锁一行
表级锁:如果事务隔离级别是序列化,将会发生整张表的锁
六、JDBC 取得数据库自动生成的主键
Connection中:
PreparedStatement prepareStatement(String sql, int autoGeneratedKeys):
autoGeneratedKeys - 指示是否应该返回自动生成的键的标志,它是
Statement.RETURN_GENERATED_KEYS 或 Statement.NO_GENERATED_KEYS 之一
PreparedStatement 中有一个方法,来得到咱们的自动生成的主键值:
ResultSet getGeneratedKeys()
七、批处理
当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。
JDBC的批量处理语句包括下面两个方法:
1.ddBatch():添加需要批量处理的SQL语句或参数
2.executeBatch():执行批量处理语句;
通常我们会遇到两种批量执行SQL语句的情况:
1.多条SQL语句的批量处理;
2.一个SQL语句的批量传参;
注意:
JDBC连接MySQL时,如果要使用批处理功能,请再url中加参数?rewriteBatchedStatements=true
PreparedStatement作批处理插入时使用values(使用value没有效果)
Statement
void addBatch(String sql):添加需要批量处理的SQL语句
int[] executeBatch();执行批量处理语句;
PreparedStatement
void addBatch()将一组参数添加到此 PreparedStatement 对象的批处理命令中
int[] executeBatch();执行批量处理语句;
关于效率测试
测试:插入100000条记录
(1)Statement不使用批处理
(2)PreparedStatement不使用批处理
(3)Statement使用批处理
(4)PreparedStatement使用批处理(效率最高)
(4)>(3)>(1)>(2)