Sql语句:
USE test;
CREATE TABLE t_account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
money INT
);
SELECT * FROM t_account;
INSERT INTO t_account VALUES(NULL,'陈如水',1000);
INSERT INTO t_account VALUES(NULL,'陈少文',1000);
DELETE FROM t_account WHERE id=2;
DELETE FROM t_account WHERE id=3;
#演示转账逻辑
START TRANSACTION;
UPDATE t_account SET money=money-100 WHERE NAME='陈如水';
UPDATE t_account SET money=money+100 WHERE NAME='陈少文';
COMMIT TRANSACTION;
#两条语句同时执行成功,或者同时执行失败,保持一致性,需要使用事务包裹
#关于事务的操作:开启事务,提交事务;
#演示事务的回滚
START TRANSACTION;
UPDATE t_account SET money=money-100 WHERE NAME='陈如水';
UPDATE t_account SET money=money+100 WHERE NAME='陈少文';
ROLLBACK;-- 已经回滚,所以sql语句相当于不执行
COMMIT;
java代码:
package test;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
* Created by Administrator on 2017/7/2.
* 演示事务在jdbc中的使用
*/
public class TestTransaction {
public static void main(String[] args){
//演示转账业务逻辑
try {
Connection conn = DBUtils.getConnection();
//打开事务,相当于start transaction
conn.setAutoCommit(false);
Statement st = conn.createStatement();
st.executeUpdate("UPDATE t_account SET money=money-100 WHERE NAME='陈如水'");
st.executeUpdate("UPDATE t_account SET money=money+100 WHERE NAME='陈少文'");
//提交事务
conn.commit();
//回滚事务(相当于不执行上面的sql语句)
//conn.rollback();
DBUtils.close(conn,null,null);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
事务
如果需要保证 两条sql语句要么同时成功,要么同时失败. 需要将这两个操作放置到一个事务中.
因为事务可以将多个sql语句"绑定"到一起执行.
核心语句:
1.打开事务 START TRANSACTION;
2.如果都成功了执行 = > 提交COMMIT;
3.如果任何一步出现问题 => 回滚 ROLLBACK; 表示sql语句执行不生效,事务结束。
事务的边界
1、默认情况下, mysql 在执行 每条sql语句时,都会自动打开一个事务,并在 语句执行之后立刻提交该事务 (自动提交事务);
2、为了将多条语句包裹到一个事务中, 我们就需要显式的打开事务(START TRANSACTION).这样数据库就不会自动提交事务,而是等待用户操作.
事务在mysql中的生命周期:
1. mysql数据库是自动事务提交的数据库. 每一条的运行都会默认(自动)开启一个事务,在语句执行成功后,自动提交事务.
2. 我们也可以使用start transaction 命令,手动控制事务.start transaction 命令代表事务打开.
3. start transaction 命令之后 , 事务结束: commit=> 代表语句执行生效,事务结束.
4. start transaction 命令之后 , 事务结束: rollback=> 代表语句执行(回滚)不生效,事务结束.
5. start transaction 命令之后 , 事务结束: 连接断开/宕机/超时,事务自动回滚.
事务的保存点:
相当于玩游戏的存档, 当一个业务 涉及多个语句 执行周期很长时, 我们可以在执行的过程中添加 保存点. 在后续的操作中,
如果出现执行失败, 就可以不用非得 回到最原点, 可以回到保存点. 节省时间。
事务在jdbc中的操作:
conn.setAutoCommit(true/false) => 打开/关闭 事务的自动提交 => 设置为false相当于执行了start transaction
conn.commit(); 事务的提交.
conn.rollback(); 事物的回滚.
保存点
conn.setSavePoint(String name);
conn.setSavePoint(); 以上两个是添加保存点的方法
conn.rollback(SavePoint sp); 该方法指定还原到某保存点
事务的特性:
A Atomicity 原子性,事务中的操作将会被视为一个整体不可分割的部分,要么都成功要么都失败.
C Consistency一致性,事务执行前和执行后 数据的一致性应得以保证.例如tom账户减去100,相应的jerry账户就多出100;
I Isolation 隔离性,当同时存在多个事务的时候,事务之间应该不收干扰.
D Durability 持久性, 事务一旦提交,数据会持久化到保存介质上.
事务的并发性造成的问题
1、脏读=> A,B两个线程同时打开两个事务,A事务读取到了B事务修改但是还没有提交的数据.
2、不可重复读=> A在两次连续的读取某条数据时,b在两次读取之间,修改了a读取的数据并提交了事务. 导致A的两次读取得到的结果不一致.
3、幻读==> A在两次连续读取表中记录数量时,B在A第一次读取之后,插入了一条新的数据,导致A的两次读取数量不一致.
数据库的隔离级别:
数据库对于以上三个问题,给出了解决方案: InnoDB => 行锁
数据库准备了以下隔离级别来规避以上问题的产生.
读未提交 read uncommitted 1 脏读,不可重复读,幻读
读已提交 read committed 2 不可重复读,幻读
可重复读 repeatable read 4 幻读(mysql默认级别)
串行化 Serializable 8
oracle 还有一个自己定义的隔离级别,就是read only(只读) 级别;
数据库中的锁机制
数据库连接池
1,数据库连接池是什么? 应用程序与数据库建立连接的过程也是需要消耗资源的;如果不做任何处理,就需要不断的创建连接,关闭连接。,
2,连接池出现的必要性?每当需要访问数据库时,不在是创建连接,而是将连接从连接池中取出,直接使用即可;使用完毕后,将连接放回到连接池中,这样连接对象就可以复用,可以达到节省资源的目的。数据库连接池是用来提供连接复用的。
数据库连接池:1)初始化连接池中的连接,2)从连接池中获取连接
实现连接池分为两大步骤:
1.准备容器(连接池) 存放连接对象,每当有需要连接的时候,从容器中取出连接返回.
2.当连接关闭时, 不能真正连接关闭,而是需要连接收回.
dbcp连接池使用 (一般都是通过配置文件配置连接参数)
//1> 直接new 连接池
BasicDataSource dataSource = new BasicDataSource();
//2> 设置参数
// 驱动
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
// url
dataSource.setUrl("jdbc:mysql:///day15");
// userName
dataSource.setUsername("root");
// password
dataSource.setPassword("1234");
//连接池中初始化多个连接
dataSource.setInitialSize(3);
//设置最大空闲连接数
dataSource.setMaxIdle(10);
//设置最小空闲连接数
dataSource.setMinIdle(3);
c3p0连接池使用(这两种连接池的使用)
package test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;
import java.sql.SQLException;
/**
* Created by Administrator on 2017/7/3.
*/
public class TestConnPool {
//测试c3p0连接池
public void fun1() throws SQLException {
//配置的名称必须是固定的 c3p0-config.xml
ComboPooledDataSource ds = new ComboPooledDataSource();
//使用完毕后销毁数据库连接池
DataSources.destroy(ds);
//使用连接池操作数据库,没有什么难的。
}
}