数据库事务
事务的概念
事务是指数据库的一个操作序列,它是由一条或多条SQL命令所组成的,这些命令不可分割,只有当事务的所有命令被成功执行后,整个事务引起的操作才会被更新到数据库,如果有一条执行失败,所有的操作都将会被取消。
MYSQL数据库共有两种方式来管理事务。
- 自动提交事务
在默认状态下MYSQL自动提交事务,即每执行一条SQL语句就提交一次事务。可以通过MYSQL的全局变量autocommit进行查看
show variables like '%commit%';
当全局变量autocommit的值为ON时,数据库事务时默认提交的。
#关闭数据库自动提交功能
#0是off,1是on
set autocommit = 0;
- 手动提交事务
手动进行事务管理步骤:
- 开启事务(strart transaction)
- 提交(commit)或回滚(rollback)事务
提交事务会将整个事务中的操作更新导数据库
回滚事务则会取消整个事务已执行的所有操作
例:
#开启事务
start transaction;
update student set age = age-1 where sid = 1;
update student set sname= 'erha' where sid = 2;
commit;
#或者
rollback;
在实际开发中,事务时并发控制的基本单位,将一组操作序列组合为一个要么成功,要么失败的单元,可以简化错误,恢复并应用程序更加可靠。
事务的ACID属性
ACID是数据库事务正确执行的四个基本要素的缩写,一个支持事务的数据库必须具有这四种特性才能保证数据的正确性
- 原子性(atomicity):整个事务中的所有操作是不可分割的,要么完全执行,要么完全不执行
- 一致性(consistency):事务完成时数据必须是一致的,即与事务开始之前数据存储中的数据处于一致状态
- 隔离性(isolation):事务与事务之间相互独立,彼此隔离,操作互不干扰
- 持久性(durability):事务一旦提交,那么对数据库中的数据的改变时永久的
数据库的隔离级别
对于数据库而言,起明显的特征时资源可以被多个用户共享。当相同的数据库资源被多个用户(多个事务)同时访问时,如果没有采取必要的隔离,就会导致各种并发问题,破坏数据的完整性。
如果不考虑隔离性,数据库将会存在以下三种并发问题:
- 脏读
一个事务读取到了另一个事务尚未提交的更改数据
- 不可重复读
一个事务读取数据后,另一个事务执行更新操作,使第一个事务无法再现前一次的读取结果
- 幻读
一个事务读取数据后,另一个事务执行插入插入操作,使第一个事务无法再现前一次的读取结果
为了解决问题,数据库规范定义了四种隔离级别,用于限定事务之间的可见性
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| read uncommitted(读未提交) | 允许 | 允许 | 允许 |
| read committed(读已提交) | 不允许 | 允许 | 允许 |
| repeatable read(可重复读) | 不允许 | 不允许 | 允许 |
| serializable(串行化) | 不允许 | 不允许 | 不允许 |
- read uncommitted(读未提交):一个事务读到另一个事务没有提交的数据。
- read committed(读已提交):一个事务读到另一个事务已经提交的数据。
- repeatable read(可重复读):一个事务中读到的数据始终一致,无论其他事务是否提交
- serializable(串行化):只能同时执行一个事务,相当于单线程
安全性最高的是serializable(串行化),最低的是read uncommitted(读未提交),越安全执行效率就越低。serializable(串行化)是以锁表的方式,使其他事务只能在锁外等待,选用级别根据实际情况而定。MYSQL默认级别为repeatable read(可重复读)。
JDBC事务处理
再JDBC的数据操作中,Connection对象为事务管理提供了三种方法
- setAutoCommit(boolean autocommit):设置是否自动提交事务
- commit():提交事务
- rollback():回滚
手动进行事务管理,需要调用setAutoCommit(false)来禁止自动提交。
数据库连接池
数据库连接池的必要性
实际开发中,建立连接是一个费时的活动,会造成系统资源和时间的大量消耗,严重的甚至会造成服务器的崩溃。如果程序出现异常而未能关闭将会导致内存的泄漏,最终导致重启数据库。因此开发中通常使用数据库连接池技术。
数据库连接池
为数据连接建立一个缓冲池。预先再缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从连接池中取出一个,用完再放回去
连接池负责分配、管理和释放资源,允许应用程序重复使用一个现有的数据库连接。有四大优势:
- 资源重用
- 更快的系统响应速度
- 新的资源分配手段
- 统一的连接管理,避免数据库连接泄漏
工作原理
- 连接池的建立;java中提供了很多容器类,可以方便构建连接池
- 连接池的管理
- 连接池的关闭
- 连接池的配置
自定义数据库连接池
用于理解连接池原理
C3P0数据库连接池
C3P0数据库连接池介绍
使用较多的开源数据库连接池之一,性能高效,支持JDBC定义的规范,拓展性好,可以和Hibernate、spring等开源框架整合使用。
它是通过核心类ComboPooledDataSource实现DataSource接口
C3P0数据库连接池使用
- 直接创建对象并设置属性
要在lib目录中导入C3P0的jar
c3p0-0.9.2-pre.jar
mchange-commons-java-0.2.3.jar
package com.itheima.jdbc.test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class TestC3P0_1 {
public static void main(String[] args) throws Exception {
//核心类
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//四项基本设置
//设置连接数据库的驱动
dataSource.setDriverClass("com.mysql.jdbc.Driver");
//设置连接数据库的路径
dataSource.setJdbcUrl("jdbc:mysql://localhost/user");
//设置数据库的用户名
dataSource.setUser("root");
//设置数据库的密码
dataSource.setPassword("root");
//其他设置
//初始化连接数为10
dataSource.setInitialPoolSize(10);
//设置最大连接数为20
dataSource.setMaxPoolSize(20);
//设置最小连接数为3
dataSource.setMinPoolSize(3);
//设置每次创建的连接数
dataSource.setAcquireIncrement(3);
//设置连接的最大空闲时间
dataSource.setMaxAdministrativeTaskTime(300);
//获得连接
dataSource.getConnection();
}
}
- 通过读取配置文件创建对象(暂时放着先学xml)
先将数据库的配置信息写入c3p0-config.xml文件中,然后通过CombolPooledDataSource类的构造方法读取配置文件并创造该类的对象。
DBCP数据库连接池
DBCP数据库连接池介绍
可以与应用服务器整合使用,也可以由应用程序独立使用。Tomcat服务器即内置了该数据库连接池。
通过BasicDataSource核心类实现DataSourse接口,还提供了BasicDataSourceFactory类用于创建BasicDataSource对象,通过调用createDataSourse()方法读取配置文件信息并返回一个连接池对象给调用者。
DBCP数据库连接池使用
1.直接创建并设置属性
commons-dbcp-1.4.jar
commons-pool-1.6.jar
package com.itheima.jdbc.test;
import org.apache.commons.dbcp.BasicDataSource;
import java.sql.SQLException;
public class TestDBCP_1 {
public static void main(String[] args) throws SQLException {
BasicDataSource dataSource = new BasicDataSource();
//基本四项设置
//设置连接数据库的驱动
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
//设置连接数据库的路径
dataSource.setUrl("jdbc:mysql://localhost/user");
//设置数据库的用户名
dataSource.setUsername("root");
//设置数据库的密码
dataSource.setPassword("root");
//其他设置
//初始化连接数为10
dataSource.setInitialSize(10);
//设置最大连接数为20
dataSource.setMaxIdle(20);
//设置最小连接数为3
dataSource.setMinIdle(3);
// 设置可以同时分配的最大活动连接数
dataSource.setMaxActive(15);
// 获得连接
System.out.println(dataSource.getConnection());
}
}
- 通过读取配置文件创建对象
先将数据库连接池的配置信息写入dbcpconfig.properties文件中,然后通过basicDataSourceFactory类读取配置信息并创建BasicDataSoure对象,最后获取。
package com.itheima.jdbc.test;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.util.Properties;
public class TestDBCP_2 {
public static void main(String[] args) throws Exception {
//用类加载器的方式加载文件
InputStream is = TestDBCP_2.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(is);
//使用BasicDataSourceFactory调用静态方法,获得dataSource
DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
System.out.println(dataSource.getConnection());
}
}
