【事务概述】
1.什么是事务?
逻辑上的一组操作,组成这组操作的各个单元要么全部成功,要么全部失败。
2.mysql事务
默认的事务:一条sql语句就是一个事务,默认就开启事务并提交事务。
手动事务:(1) 显示的开启一个事务 -- start transaction
(2) 事务提交 -- commit 代表从开启事务到提交事务 中间所有的sql语句都认为有效,真正的更新数据库。
(3) 事务的回滚 -- rollback 从开启事务到回滚事务 中间所有sql操作都认为无效,数据库没更新。
【JDBC事务操作】
(1). 默认是自动事务 执行sql语句:executeUpdate(),每执行一次executeUpdate()方法代表事务自动提交。
(2). 手动事务 开启事务:con.setAutoCommit(false); 提交事务:con.commit(); 回滚事务:con.rollback();
注意:控制事务的connextion必须是同一个。
【DBUtils事务操作】
(1) 有参构造:QueryRunner runner = new QueryRunner(DataSource dataSource) 将数据源(连接池)作为参数传入QueryRunner,QueryRunner会从连接池中获得一个数据库连接资源操作数据库,所以可以直接使用无Connection参数的update方法即可操作数据库。
(2) 无参构造:QueryRunner runner = new QueryRunner() 没有将数据源作为参数传入QueryRunner,操作数据库的时候,要使用有Connection参数的方法。
【ThreadLocal工具类】-- 在一个线程中共享数据
ThreadLocal工具类底层就是一个Map,key存放的当前线程,value存放共享的数据。
ThreadLocal操作: set(value) get() remove()
c3p0-config.xml 数据库配置文件
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///mybase1</property>
<property name="user">root</property>
<property name="password">123</property>
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<named-config name="namedConfig">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///mybase1</property>
<property name="user">root</property>
<property name="password">123</property>
</named-config>
</c3p0-config>
【ThreadLocal 在当前线程中存储Connection】
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3p0Utils {
// 使用默认配置信息 -- 自动读取c3p0-config.xml中的配置信息
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 创建ThreadLocal -- 用于在当前线程中共享数据
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
// 静态方法获得连接池
public static DataSource getDataSource() {
return dataSource;
}
// 静态方法获得连接池
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 开启事务
public static void startTransaction() throws SQLException {
Connection con = getCurrentConnection();
con.setAutoCommit(false);
}
// 回滚事务
public static void rollback() throws SQLException {
getCurrentConnection().rollback();
}
// 提交事务
public static void commit() throws SQLException {
Connection con = getCurrentConnection();
con.commit();
// 将Connection从ThreadLocal中删除
tl.remove();
con.close();
}
// 获得当前线程绑定的Connection
public static Connection getCurrentConnection() throws SQLException {
// 从ThreadLocal寻找,当前线程是否有对应的Connection
Connection con = tl.get();
if(con == null) {
// 获得新的Connecton资源
con = getConnection();
// 将Connection资源绑定到ThreadLocal
tl.set(con);
}
return con;
}
}
【事务的特性】
(1)原子性(Automicity) 原子性是指事务一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
(2)一致性(Consistency) 事务前后数据的完整性必须保持一致。
(3)隔离性(Isolation) 多个用户并发访问数据库时,一个用户的事物不能被其他用户的事物所干扰,多个并发事物之间数据要隔离。
(4)持久性(Durability)一个事务一旦被提交,它对数据库中数据的改变是持久性的,接下来即使数据库发生故障也不应该对其有任何影响。
【并发访问问题】--- 由隔离性引起
(1)脏读:B事务读到了A事务未提交的数据。--- 要求B事务要读取A事务提交的数据。
(2)不可重复读:一个事务中 两次读取到数据内容不一致 --- 要求的是一个事务中多次读取到的数据是一致的。
(3)虚读/幻读: 一个事务中 两次读取的数据的数量不一致 --- 要求在一个事务多次的数据的数量是一致的。
【解决并发问题】--- 设置隔离级别
(1)read uncommitted: 读取尚未提交的数据:哪个问题都不能解决。
(2)read committed: 读取已经提交的数据:可以解决脏读。--- oracle 默认的。
(3)repeatable read : 重读读取:可以解决脏读 和 不可重复读。--- mysql 默认的。
(4)serializable:串行化:可以解决脏读,不可重复读 和 虚读。--- 相当于锁表。
查看mysql数据库默认的隔离级别:select @@tx_isolation
设置事务的隔离级别:set session transaction isolation level 事务隔离级别。
【总结】
mysql的事务控制:
开启事务:start transaction
提交事务:commit 回滚:rollback
JDBC 事务控制
开启事务:con.setAutocommit(false) 提交事务:con.commit() 回滚:con.rollback()
DBUtils的事务控制 也是通过jdbc控制
ThreadLocal:实现的是通过线程绑定的方式传递参数
概念:
事务的特性:ACID
并发问题:脏读、不可重读、幻读
解决并发问题:设置隔离级别
read uncommittedread committedrepeatable read(mysql默认)
serialazable
隔离级别的性能:
read uncommitted>read committed>repeatable read>serialazable安全性:
read uncommitted<read committed<repeatable read<serialazable