文章目录
数据库引擎:
默认使用:Innodb
如何更改默认数据库引擎
找到MySQL配置文件mysql.ini,首先将其备份(这是个好习惯,当需要更改Linux上配置文件时)即
cp mysql.ini mysql.ini.bak
如何在建表时设置引擎及建表后更改引擎
建表时设置引擎:
create table 表名(
…
)ENGINE=引擎名
事物
事物是指逻辑上的一组操作,组成这组操作的各个单元,要么全部执行成功,要么全部实行失败。
事务 的基本原理
1、不用事务,直接作用于表
2、用了事务之后
例如:张三–李四转账
– 事物
CREATE TABLE account(
id INT PRIMARY KEY auto_increment,
name
VARCHAR(10),
money DOUBLE
);
INSERT INTO account(name,money) VALUES(‘张三’,1000),(‘李四’,1000);
– 张三给李四转账1000块钱
UPDATE account SET money=money-1000 WHERE name=‘张三’;
UPDATE account SET money=money+1000 WHERE name=‘李四’;
数据库开启事务的命令:
Connection接口下面的方法:
void setAutoCommit(boolean autoCommit);autoCommit - 为 true 表示启用自动提交模式;为 false 表示禁用自动提交模式(默认情况下就是true)(可以用这个来防止转账失败但是仍然修改金额的发生)
void commit();手动提交事物。
void rollback();回滚(出现异常的时候,所有已经执行成功的代码需要回退到事务开始前的状态)
默认情况下,Connetion对象处于自动提交模式下,这意味着他在执行每个语句后都会自动提交更改。
如果禁用自动提交模式,那么提交更改就必须显示调用commit方法,否则就无法保存数据库的更改。
public void test1() {
Connection connection = null;
PreparedStatement preparedStatement = null;
String sql1 = "UPDATE account SET money=money-1000 WHERE name='张三'";
String sql2 = "UPDATE account SET money=money+1000 WHERE name='李四'";
try {
connection = JDBCUtil.getConnection();
// 为false,表示禁用自动提交(默认情况是true)
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement(sql1);
System.out.println(preparedStatement);
preparedStatement.executeUpdate();
// ArithmeticException: / by zero
int i = 3 / 0;
preparedStatement = connection.prepareStatement(sql2);
System.out.println(preparedStatement);
preparedStatement.executeUpdate();
// setAutoCommit(false)改成false之后,不会提交数据库,只有调用connection.commit()才提交
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
JDBCUtil.close(connection, preparedStatement, null);
}
}
事务四个基本特征或 ACID 特性:
1、Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
2、Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
3、Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务concurrent并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。
4、Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
Spring的事物传播特性(属性)
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:一个方法运行在了一个开启了事务的方法中时,当前方法是使用原来的事务还是开启一个新的事务。
Spring定义了7种类传播行为:
Propagation:
PROPAGATION_REQUIRED:需要, 如果存在一个事务,则支持当前事务, 如果没有事务则开启(原来有就使用原来事物,没有就创建事物,一般Service的中更新类的操作)
PROPAGATION_SUPPORTS:支持, 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行(原来有就使用原来事物,没有就算了,一般Service的中查询操作)
PROPAGATION_REQUIRES_NEW:总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
PROPAGATION_MANDATORY: 必要的 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
PROPAGATION_NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务。
PROPAGATION_NEVER:绝不 总是非事务地执行,如果存在一个活动事务,则抛出异常
PROPAGATION_NESTED:嵌套的 如果有就嵌套、没有就开启事务
事务传播属性可以在@Transactional注解的propagation属性中定义。
数据库事务并发Concurrent问题
1、脏读
(当前事物读到了其他事物更新但是还没有提交的值就是脏读)①Transaction01将某条记录的AGE值从20修改为30。②Transaction02读取了Transaction01更新后的值:30。Read Uncommited③Transaction01回滚,AGE值恢复到了20。④Transaction02读取到的30就是一个无效的值。
只有脏读是读取了别人更新但是还没有提交到数据库的数据,不可重复读和幻读都是读取已经提交数据库的数据。
2、不可重复读
unrepeatable read
①Transaction01读取了AGE值为20。
②Transaction02将AGE值修改为30,提交数据库。
③Transaction01再次读取AGE值为30,和第一次读取的不一样
这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
3、幻读
①Transaction01读取了Student表中的一部分数据
②Transaction02向Student表中插入了新的行
③Transaction01读取了Student表时,多出了一些行。
事物隔离级别 isolate
数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。
隔离级别越高,数据一致性就越好,但并发性越弱。
1、读未提交:READ UNCOMMITTED
允许Transaction01读取Transaction02未提交的修改。
2、读已提交:READ COMMITTED
要求Transaction01只能读取Transaction02已提交的修改。
3、可重复读:REPEATABLE READ
确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。
4、串行化:SERIALIZABLE
确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。(单线程,在一个请求中,其他线程读都不可以)
可以在@Transactional的isolation属性中设置隔离级别,并不是隔离级别越高越好,一般是READ COMMITTED读已提交。
Isolation.REPEATABLE_READ:可重复读,MySQL默认的隔离级别
Isolation.READ_COMMITTED:读已提交,Oracle默认的隔离级别,开发时通常使用的隔离级别