一、事务
种机制,某个业务中多次调用dao完成多个sql同时执行,要么同时执行成功/要么同时执行失败
否则,就出现数据紊乱! 使用事务管理(JDBC方式操作)
二、需求
用户发送请求,通过连接池获取Connection对象
Connection:管理事务的功能void setAutoCommit(boolean autoCommit) throws SQLException
默认情况下,新创建的连接对象处于自动提交模式 参数为true,声明为false,禁用自动提交,需要收到提交sql
void rollback() throws SQLException:当前执行提交之前,如果sql发生异常,将撤销之前的所有操作
void commit() SQLException:如果执行过程中没有问题或者回滚了,都提交事务,将之前的所有操作永久保存!
三、步骤:
1、properties
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb_01?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000
2、 DruidJdbcUtils工具
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @author Kuke
* @date 2021/8/18
* 工具类---->DataSource----->获取数据库的连接对象 Connection以及后期管理事务
*
* 获取连接对象----静态方法
* 关闭资源-----静态方法
*/
public class DruidJdbcUtils {
//成员变量位置
private static DataSource ds ;
//为了保证线程安全:每一线程使用自己的Connection (张三/李四)
private static ThreadLocal<Connection> t1 = new ThreadLocal<>() ; //提供线程的局部变量保存连接对象
//构造方法私有化
private DruidJdbcUtils(){}
//静态代码块
static{
try {
//读取数据库连接池的配置文件----->通过DruidDataSourceFactory工厂类创建DataSource
//创建一个属性集合列表
Properties prop = new Properties() ;
//读取druid.properties
InputStream inputStream = DruidJdbcUtils.class.getClassLoader().
getResourceAsStream("jdbc.properties");
//将资源文件所在的输入流加载列表中
prop.load(inputStream);
ds = DruidDataSourceFactory.createDataSource(prop); //底层子实现类:DruidDataSource
//System.out.println("数据源获取成功");
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//提供静态方法:单独获取数据源
public static DataSource getDataSource(){
return ds ;
}
//获取连接对象Connection静态功能
public static Connection getConnection(){
//从ThreadLocal中获取局部变量的副本:Connection
/**
* public T get() :从线程中获取局部变量的副本!
*/
Connection conn = null ;
try {
conn = t1.get();
if(conn==null){
//如果空,需要从数据库的连接池中获取连接对象
conn = ds.getConnection();
//获取到之后,每一线程执行自己的Connection
//将获取到的连接对象 绑定到当前线程中
t1.set(conn);
}
//如果不为空,说明ThreadLocal线程中已经存在Connection
return conn ; //
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//关闭(释放资源)资源
public static void close(ResultSet rs, Statement stmt,Connection conn) {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
//关闭之后,归还到连接池中,需要从当前线程中解绑
t1.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close( Statement stmt,Connection conn) {
close(null,stmt,conn);
}
//事务管理代码 --- 加入
//定义开启事务的方法
//定义回滚的方法
public static void rollback() throws SQLException {
Connection connection = DruidJdbcUtils.getConnection();
//调用回滚方法
connection.rollback();
//使用完毕,归还连接池中
connection.close();
//从当前线程中解绑
t1.remove();
}
//定义提交的方法---->需要将当前线程中绑定的Connetion remove掉
public static void main(String[] args) {
// DataSource ds = DruidJdbcUtils.getDataSource();
//System.out.println(ds);
Connection connection = DruidJdbcUtils.getConnection();
System.out.println(connection);
}
}
3、实现类
public class JdbcTransactionDemo {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement stmt1 = null;
PreparedStatement stmt2 = null;
try {
//通过DruidJdbcUtils获取连接对象
connection = DruidJdbcUtils.getConnection();
//开启事务---将自动提交禁用调用,参数为false,手动提交
connection.setAutoCommit(false);
//准备sql语句
String sql1 = "update account set balance = balance - ? where id = ?" ;
//创建预编译对象对sql1进行预编译
stmt1 = connection.prepareStatement(sql1);
//参数赋值
stmt1.setInt(1,500);
stmt1.setInt(2,1);
//执行更新
stmt1.executeUpdate() ;
//程序出问题了
// int i = 10 /0 ;
String sql2 = "update account set balance = balance + ? where id = ? " ;
//创建预编译对象对sql2进行预编译
stmt2 = connection.prepareStatement(sql2);
//参数赋值
stmt2.setInt(1,500);
stmt2.setInt(2,2);
//执行更新
stmt2.executeUpdate() ;
//如果没有问题,正常提交
connection.commit();
System.out.println("转账成功...");
} catch (SQLException e) {
//处理异常: 直接事务回滚
//有异常,执行catch语句,就回滚
try {
System.out.println("程序出问题了...");
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
//e.printStackTrace();
}
//释放资源
DruidJdbcUtils.close(stmt1,connection);
DruidJdbcUtils.close(stmt2,connection);
}
}