1. JDBC 的相关 API 小结  832

封装 JDBCUtils和事务_事务

封装 JDBCUtils和事务_事务_02

2. 封装 JDBCUtils 【关闭连接, 得到连接】  833

2.1 说明

在jdbc操作中,获取连接和释放资源是经常使用到可以将其封装JDBC连接的具类JDBCUtils

2.2 代码实现

实际使用使用工具类 JDBCUtils

代码在com.stulzl.utils.

JDBCUtils      833
package com.stulzl.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

//这是一个工具类,完成 mysql 的连接和关闭资源   833
public class JDBCUtils {
    //定义相关的属性(4 个), 因为只需要一份,因此,我们做出 static
    private static String user; //用户名
    private static String password; //密码
    private static String url; //url
    private static String driver; //驱动名

    //再static代码块中去初始化
    static{
        try {
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\mysql.properties"));
            //读取相关的属性数据
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            driver = properties.getProperty("driver");
        } catch (IOException e) {
            //在实际开发中,我们可以这样处理
            //1. 将编译异常转成 运行异常
            //2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便.
            throw new RuntimeException(e);
        }
    }

    //连接数据库,返回Connection
    public static Connection getConnection(){
        try {
            return DriverManager.getConnection(url,user,password);
        } catch (SQLException e) {
            //1. 将编译异常转成 运行异常
            //2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便.
            throw new RuntimeException(e);
        }
    }

    //关闭相关资源
    //分析可能要关闭的资源
    /*
        1. ResultSet 结果集
        2. Statement 或者 PreparedStatement
        3. Connection
        4. 如果需要关闭资源,就传入对象,否则传入 null
    */
    public static void close(ResultSet set, Statement statement,Connection connection){
        try {
            //判断是否为null
            if(set!=null){
                set.close();
            }
            if(statement!=null){
                statement.close();
            }
            if(connection!=null){
                connection.close();
            }
        } catch (SQLException e) {
            //1. 将编译异常转成 运行异常
            //2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便.
            throw new RuntimeException(e);
        }
    }

}
测试类JDBCUtils_Use           834
package com.stulzl.utils;

import org.junit.jupiter.api.Test;

import javax.annotation.processing.SupportedAnnotationTypes;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

//该类演示如何使用JDBCUtils工具类,完成dml和select  834
public class JDBCUtils_Use {
    public static void main(String[] args) {

    }
    @Test
    public void testDML(){
        //1.得到连接
        Connection connection = null;
        //2.组织一个sql语句
        String sql = "update actor set name=? where id = ?";
        PreparedStatement preparedStatement=null;
        try {
            connection = JDBCUtils.getConnection();
            //3.创建preparedStatement对象
            preparedStatement = connection.prepareStatement(sql);

            //4. 给占位符赋值
            preparedStatement.setString(1,"周星驰");
            preparedStatement.setInt(2,2);

            //执行
            preparedStatement.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.close(null,preparedStatement,connection);
        }
    }
}
配置文件再src下面   mysql.properties
user=root
password=lzl
url=jdbc:mysql://localhost:3306/hsp_db02
driver=com.mysql.jdbc.Driver

2.2.1  JDBCUtils的select使用  835

 testSelect()方法
//JDBCUtils的select使用  835
    @Test
    public void testSelect(){
        //1.得到连接
        Connection connection = null;
        //2.组织一个sql语句
        String sql = "select * from actor where id=?";
        PreparedStatement preparedStatement=null;
        ResultSet set = null;
        try {
            connection = JDBCUtils.getConnection();
            //3.创建preparedStatement对象
            preparedStatement = connection.prepareStatement(sql);

            //4. 给占位符赋值
            preparedStatement.setInt(1,2);

            //执行,得到结果集
            set = preparedStatement.executeQuery();

            //遍历该结果集
            while(set.next()){
                int id = set.getInt("id");//这里提示("id")可以直接写,也可以写数字(按对应顺序)
                String name = set.getString("name");
                String sex = set.getString("sex");
                Date borndate = set.getDate("borndate");
                String phone = set.getString("phone");
                System.out.println(id + "\t" + name + "\t" + sex
                        + "\t" + borndate + "\t" + phone);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.close(set,preparedStatement,connection);
        }
    }
}

3. 事务  836

3.1 基本介绍   836

1. JDBC程序中当一 个Connection对象创建时,默认情况下是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。

2. JDBC程序中为了让多个 SQL语句作为一个整体执行,需要使用事务

3.调用Connection的setAutoCommit(false)可以取消自动提交事务

4.在所有的SQL语询都成功执行后,调用Connection的commit();方法提交事务

5.在其中某个操作失败或出现异常时, 调用Connection的rollback();方法回滚事务

3.2 应用实例   837

模拟经典的转账业务

封装 JDBCUtils和事务_sql_03

3.3 不使用事务可能出现的问题模拟-模拟经典的转账业务   837

3.4 使用事务解决上述问题-模拟经典的转账业务  837

3.3和3.4代码在 com.stulzl.transaction_

Transaction_

package com.stulzl.transaction_;

import com.stulzl.utils.JDBCUtils;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

//演示JDBC中如何使用事务   837
public class Transaction_ {

    //不使用事务
    @Test
    public void noTransaction(){
        //1.得到连接
        Connection connection = null;
        //2.组织一个sql语句
        String sql = "update account1 set balance=balance-100 where id = 1";
        String sql2 = "update account1 set balance=balance+100 where id = 2";
        PreparedStatement preparedStatement=null;
        try {
            connection = JDBCUtils.getConnection();// 在默认情况下,connection 是默认自动提交
            //3.创建preparedStatement对象
            //这里就是给马云扣100
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeUpdate();//执行第一条sql

            //这里抛出异常,我们的目的是为了让马云转账出去,但是马化腾接收不到(因为执行遇到异常后
            // 面的代码将不再运行) 让我们更加直观的感受接下来事务操作
            int i = 1/0;

            //这里就是给马化腾加100
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();//执行第二条sql2

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.close(null,preparedStatement,connection);
        }
    }


    //使用事务来解决
    @Test
    public void useTransaction(){
        //1.得到连接
        Connection connection = null;
        //2.组织一个sql语句
        String sql = "update account1 set balance=balance-100 where id = 1";
        String sql2 = "update account1 set balance=balance+100 where id = 2";
        PreparedStatement preparedStatement=null;
        try {
            connection = JDBCUtils.getConnection();// 在默认情况下,connection 是默认自动提交
            //将connection设置为不自动提交
            connection.setAutoCommit(false);//相当于开启了事务
            //3.创建preparedStatement对象
            //这里就是给马云扣100
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeUpdate();//执行第一条sql

            //int i = 1/0;//这里抛出异常

            //这里就是给马化腾加100
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();//执行第二条sql2

            //这里提交事务
            connection.commit();

        } catch (SQLException e) {
            //这里我们可以进行回滚,即撤销执行的 SQL
            //默认回滚到事务开始的状态
            System.out.println("执行发生了异常,撤销执行的 sql");
            try {
                connection.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.close(null,preparedStatement,connection);
        }
    }
}

代码在E:\java学习\初级\course170\db_

java_transaction

-- 创建表   837
CREATE TABLE account1(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(32) NOT NULL DEFAULT'',
	balance DOUBLE NOT NULL DEFAULT 0) CHARACTER SET utf8;
-- 添加数据
INSERT INTO account1 VALUES(NULL, '马云',3000);

INSERT INTO account1 VALUES(NULL, '马化腾',10000);

SELECT * FROM account1